SpringSecurity6.0版本 CSRF验证的处理

问题描述

6版本(starter 3版本)之前,我们可以简单地通过如下代码开启CSRF验证,并且将token通过Cookie提供给前端

http.csrf()
	.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
;

默认设置下前端可以从XSRF-TOKEN字段拿到token,然后把它丢到请求header中的X-XSRF-TOKEN字段中即可

6版本之后会发现单纯这样开启时按照以往的请求方式会被拦截并302到登陆界面,此时,cookie里有XSRF-TOKEN字段,而302的网页里也有一段

<input name="_csrf" type="hidden" value="xsAQ1pzqT6wQB6SZxE8QXANbvNNXV483n1xCBpbhmQKqRRO_p_J04avffM89Y5SgoWIkPTE4kbFgZLoa_G91ZKXQrDuddCeH" />

而网页里的这个才是真正的 token ,cookie里的那个是无效的。

解决方案

将上述开启代码改为

http.csrf()
	.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
    .csrfTokenRequestHandler(new CsrfTokenRequestAttributeHandler())
;

问题追踪

CSRF验证由CsrfFilter类负责,查看该类的doFilterInternal方法,以debug模式运行发现这里的actualToken null导致匹配不成功

String actualToken = this.requestHandler.resolveCsrfTokenValue(request, csrfToken);

其中requestHandler的定义为

private CsrfTokenRequestHandler requestHandler = new XorCsrfTokenRequestAttributeHandler();

查看该方法的实现

@Override
	public String resolveCsrfTokenValue(HttpServletRequest request, CsrfToken csrfToken) {
    
    
		String actualToken = super.resolveCsrfTokenValue(request, csrfToken);
		return getTokenValue(actualToken, csrfToken.getToken());
	}

debug模式运行发现这里的在执行了父类的方法后actualToken 是有值的,那么罪魁祸首就是getTokenValue这个方法,这是一个静态方法,老实说它写了啥我看不懂

但是我们发现XorCsrfTokenRequestAttributeHandler这个类有一个父类CsrfTokenRequestAttributeHandler,它没有重写resolveCsrfTokenValue方法,而且有无参构造方法,那么直接new一个覆盖原定义就好了。

猜你喜欢

转载自blog.csdn.net/hjg719/article/details/128290380