ToB企服应用市场:ToB评测及商务社交产业平台

标题: SpringSecurity CSRF传入正确雷同的token无法登陆 [打印本页]

作者: 我可以不吃啊    时间: 2025-2-12 12:24
标题: SpringSecurity CSRF传入正确雷同的token无法登陆
原文
前因

当我根据https://spring.io/guides/tutorials/spring-boot-oauth2 教程去实现一个oauth2demo时,点击logout始终无法成功登出,报错403,但是我检查request-header中x-xsrf-token和cookie中的XSRF-TOKEN的值雷同。https://stackoverflow.com/questions/74447118/csrf-protection-not-working-with-spring-security-6最后在这个回复中得到了解决办法。
简单总结:在Spring Security 5.8及更高版本中,默认利用XorCsrfTokenRequestAttributeHandler匹配token,这就需要前端传入的token不能是raw token,详细解决可以参考这个文档:https://docs.spring.io/spring-security/reference/servlet/exploits/csrf.html#csrf-integration-javascript
调试过程

如何找到该问题的源头:在application.yml 中增长:
  1. logging:
  2.   level:
  3.     org.springframework: trace
复制代码
debug时点击logout按钮,会发现控制台报错: o.s.security.web.csrf.CsrfFilter: Invalid CSRF token found for http://localhost:8080/logout 。以是我就开始一步步在CsrfFilter里进行调试。
根据报错信息,可以很直接的找到关键的方法为
  1. public final class CsrfFilter extends OncePerRequestFilter {
  2.                 @Override
  3.         protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
  4.                         throws ServletException, IOException {
  5.                         .....
  6.                 CsrfToken csrfToken = deferredCsrfToken.get();
  7.                 String actualToken = this.requestHandler.resolveCsrfTokenValue(request, csrfToken);
  8.                 if (!equalsConstantTime(csrfToken.getToken(), actualToken)) {
  9.                         boolean missingToken = deferredCsrfToken.isGenerated();
  10.                         this.logger
  11.                                 .debug(LogMessage.of(() -> "Invalid CSRF token found for " + UrlUtils.buildFullRequestUrl(request)));
  12.                         AccessDeniedException exception = (!missingToken) ? new InvalidCsrfTokenException(csrfToken, actualToken)
  13.                                         : new MissingCsrfTokenException(actualToken);
  14.                         this.accessDeniedHandler.handle(request, response, exception);
  15.                         return;
  16.                 }
  17.                 filterChain.doFilter(request, response);
  18. }
复制代码
解释

无论是看我开头提到总结的或是观察CsrfFilter 代码,会发现默认利用 XorCsrfTokenRequestAttributeHandler ,比较时会先进行处理(问了ai,该handler期望header传入的token的格式应该为Base64(随机字节+(TOKEN ⊕ 随机字节)) ,以是才会有两倍长度比较的条件。而我们根据例子传入的普通原token。以是不能成功)。
解决

详细解决可以参考这个文档:https://docs.spring.io/spring-security/reference/servlet/exploits/csrf.html#csrf-integration-javascript,简单来说header传入的token利用CsrfTokenRequestAttributeHandler 处理即可。
额外提一下,解决方法中.csrfTokenRequestHandler(new SpaCsrfTokenRequestHandler()) 这里注册自定义handler现实上是替换掉了默认的XorCsrfTokenRequestAttributeHandler ,详细实现是在CsrfConfigurer.configure(H http) 。
题外话

写这类的内容时,实在是很难把控内容的精细程度。一方面是写给我自己回顾,一方面也是盼望能资助到碰到雷同问题的人。如果写的过细,以我自己的心性来说,我肯定是没耐心读的。如果写的太粗糙,那么又无法解决问题。以是我是以我现实如何发现,调试解决这个问题的流程进行记载的,而不是对相干代码从头至尾进行讲解。
这也让我想到另一个很常见的问题,即很多人提问如何提升自己时,说到相干优秀框架的源码读不进去。这段雷同的CsrfFilter 代码,如果我没碰到这个问题,而是直接开始阅读,我肯定没耐心去调试,去搞懂很多细节。大概还是得多去尝试直接写一些demo,通过解决问题来学习。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4