spring-boot - Spring Security:通过扩展 CsrfRepository 自定义 CSRF 实现
问题描述
我正在尝试通过实现CsrfRepository
Spring Security 提供的接口在我的 Spring Boot 应用程序中创建自定义的 CSRF 实现。
下面是我的自定义存储库的样子:
public class CustomCookieCsrfTokenRepository implements CsrfTokenRepository {
static final String DEFAULT_CSRF_COOKIE_NAME = "XSRF-TOKEN";
static final String DEFAULT_CSRF_PARAMETER_NAME = "_csrf";
static final String DEFAULT_CSRF_HEADER_NAME = "X-XSRF-TOKEN";
@Override
public CsrfToken generateToken(HttpServletRequest request) {
return new DefaultCsrfToken(this.DEFAULT_CSRF_HEADER_NAME, this.DEFAULT_CSRF_PARAMETER_NAME, createNewToken());
}
@Override
public void saveToken(CsrfToken token, HttpServletRequest request, HttpServletResponse response) {
String tokenValue = token == null ? "" : token.getToken();
Cookie cookie = new Cookie(this.DEFAULT_CSRF_COOKIE_NAME, tokenValue);
cookie.setSecure(request.isSecure());
response.addCookie(cookie);
}
@Override
public CsrfToken loadToken(HttpServletRequest request) {
Cookie cookie = WebUtils.getCookie(request, this.DEFAULT_CSRF_COOKIE_NAME);
if (cookie == null) {
return null;
}
String token = cookie.getValue();
if (!StringUtils.hasLength(token)) {
return null;
}
return new DefaultCsrfToken(this.DEFAULT_CSRF_HEADER_NAME, this.DEFAULT_CSRF_PARAMETER_NAME, token);
}
private String createNewToken() {
String unsignedToken = UUID.randomUUID().toString();
return RSAUtil.signMessage(unsignedToken, privateKey);
}
}
问题:如您所见,我想使用私钥签署我的 cookie 值并使用公钥对其进行验证。问题是这个验证逻辑应该在哪里发生?我猜loadToken()
方法可以具有验证签名的逻辑。这是正确的地方还是应该在其他地方进行?
有人可以提供一些关于如何以及在哪里处理这个问题的片段或示例吗?
解决方案
不,验证逻辑应该在您的自定义 CsrfTokenRepository 实现 的generateToken(HttpServletRequest request)中。
saveToken (CsrfToken token, HttpServletRequest request, HttpServletResponse response)应该保存令牌(或者当传递的 'token' 参数为空时删除保存的令牌)并且loadToken(HttpServletRequest request) 应该返回现有保存的令牌(由 saveToken 保存方法)用于当前请求/会话;
@Component
public class CustomCsrfTokenRepository implements CsrfTokenRepository {
static final String DEFAULT_CSRF_PARAMETER_NAME = "_csrf";
static final String DEFAULT_CSRF_HEADER_NAME = "X-XSRF-TOKEN";
private String parameterName = DEFAULT_CSRF_PARAMETER_NAME;
private String headerName = DEFAULT_CSRF_HEADER_NAME;
private String cookieName = "USER_INFO";
private static final String DEFAULT_CSRF_TOKEN_ATTR_NAME = CustomCsrfTokenRepository2.class
.getName().concat(".CSRF_TOKEN");
private String sessionAttributeName = DEFAULT_CSRF_TOKEN_ATTR_NAME;
@Override
public CsrfToken generateToken(HttpServletRequest request) {
Cookie cookie = WebUtils.getCookie(request, this.cookieName);
if (cookie == null) {
return new DefaultCsrfToken(this.headerName, this.parameterName,
createNewToken());
}
String cookieValue = cookie.getValue();
String token = cookieValue.split("\\|")[0];
if (!StringUtils.hasLength(token)) {
return new DefaultCsrfToken(this.headerName, this.parameterName,
createNewToken());
}
return new DefaultCsrfToken(this.headerName, this.parameterName, token);
}
@Override
public void saveToken(CsrfToken token, HttpServletRequest request,
HttpServletResponse response) {
if (token == null) {
HttpSession session = request.getSession(false);
if (session != null) {
session.removeAttribute(this.sessionAttributeName);
}
}
else {
HttpSession session = request.getSession();
session.setAttribute(this.sessionAttributeName, token);
}
}
@Override
public CsrfToken loadToken(HttpServletRequest request) {
HttpSession session = request.getSession(false);
if (session == null) {
return null;
}
return (CsrfToken) session.getAttribute(this.sessionAttributeName);
}
private String createNewToken() {
return UUID.randomUUID().toString();
}
}
您需要在 HttpSecurity 配置中设置 customCsrfRepoImpl bean,如下所示
@Configuration
@EnableWebSecurity
public class SecurityConfigurarion extends WebSecurityConfigurerAdapter implements WebMvcConfigurer {
@Autowired
private CsrfTokenRepository customCsrfTokenRepository; //your custom csrfToken repository impl class
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.csrf().csrfTokenRepository(customCsrfTokenRepository) //set your custom csrf impl in httpSecurity
.and()
.authorizeRequests()
.antMatchers(permittedUrlsArr).permitAll()
.anyRequest().authenticated()
.and()
.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint)
.and()
.logout()
}
}
推荐阅读
- sass - Sass 将变量转换为字符串
- python - 如何检查 Python3 中的用户输入?
- javascript - d3.json 请求成功但收到错误消息
- android - Android MVP 和生命周期架构组件
- php - Instagram 应用正在从 URL 中删除返回 URL
- c# - Entity Framework Core 2.1 链接 OnModelBuilder HasKey 和 HasData
- php - PHPExcel:如何交替行颜色
- c# - 超过 2 个视频一个接一个,没有在 C# 中转换
- aws-lambda - 将 AWS 标签编辑器与 lambda 集成
- java - 无法在 Java 中将字符串转换为日期