【问题标题】:Spring security csrf not working with spring-sessionSpring security csrf 不适用于 spring-session
【发布时间】:2014-11-29 18:27:07
【问题描述】:

我使用的是 spring-session 版本 1.0.0.M1,我已将其配置为使用 MapSessionRepository: sessionFilterChainReg.addMappingForServletNames(EnumSet.of(DispatcherType.REQUEST), false, dispatcherServletReg.getName());

@Bean(name = {"defaultSessionFilter", "sessionFilter"})
public SessionRepositoryFilter sessionFilter() {
    return new SessionRepositoryFilter((SessionRepository) applicationContext.getBean("sessionRepository"));
}


@Bean(name = { "defaultSessionRepository", "sessionRepository" })
public SessionRepository defaultSessionRepository() {
    return new MapSessionRepository();
}

然后在 web-config 中:

    final FilterRegistration sessionFilterChainReg = servletContext.addFilter("sessionFilter", DelegatingFilterProxy.class);

所以我的 register.jsp 中有以下输入隐藏元素:

<input type="hidden" id="${_csrf.parameterName}" name="${_csrf.parameterName}" value="${_csrf.token}"/>

我可以看到页面使用正确的 CSRF 令牌呈现。当我提交 POST 请求时,触发 CSRF 过滤器并将令牌正确传递给过滤器,该过滤器调用 HttpSessionCsrfTokenRepository:loadToken 并在第 66 行看到:

HttpSession session = request.getSession(false);

现在会话为空,因此存储库返回空 CSRF 令牌,然后抛出 MissingCsrfTokenException。我还有什么需要配置的吗?

这是第 66 行时的堆栈跟踪(还有很多,但我想这是它的相关部分):

at org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository.loadToken(HttpSessionCsrfTokenRepository.java:66)
  at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:75)
  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
  at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
  at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
  at org.springframework.security.web.access.channel.ChannelProcessingFilter.doFilter(ChannelProcessingFilter.java:144)
  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
  at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
  at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
  at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344)
  at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261)
  at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1632)
  at org.springframework.session.web.SessionRepositoryFilter.doFilterInternal(SessionRepositoryFilter.java:83)
  at org.springframework.session.web.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:66)
  at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344)
  at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261)
  at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1632)

【问题讨论】:

  • CSRF 支持不会创建会话,直到您准备好包含 CSRF 令牌的视图。你在哪里使用 CSRF 令牌?您需要一个包含 CSRF 令牌的视图(即 JSP、Thymeleaf 模板、响应标头等)。另一件要尝试的事情是它是否可以在没有 Spring Session 的情况下工作?
  • 嗨 Rob,我更新了问题。是的,它在没有 spring 会话的情况下运行良好,并且 CSRF 令牌正确传递给过滤器,但是在 HttpSessionCsrfTokenRepository:loadToken:66 上返回的会话为空。
  • 您能否查看请求以查看存在哪些 cookie?可能与github.com/spring-projects/spring-session/issues/34有关。如果您看到多个会话cookie,则应将其全部删除,然后重试。
  • 嗨 Rob,我有很多 cookie(大约 35 个),只有 1 个称为 SESSION。我删除了所有 cookie 并再次尝试,但结果是一样的 - 我得到 MissingCsrfTokenException。另外我刚刚注意到不仅注册表不起作用,而且登录表单现在也坏了 - 完全相同的问题。
  • 当您向 HttpSessionCsrfTokenRepository:loadToken:66 添加调试点时,能否将调用堆栈从 IDE 复制/粘贴到帖子中?

标签: spring-security spring-session


【解决方案1】:

发现问题 - 我自己有一个 Filter,它包裹了 HttpServletRequest 对象,并且过滤器在 SessionRepositoryFilter 之前触发。我不确定这是否正确,但在SessionRepositoryFilter 之后强制它触发我这样做了:

@Bean(name = {"defaultSessionFilter", "sessionFilter"})
public Filter sessionFilter() {
    CompositeFilter compositeFilter = new CompositeFilter();
    compositeFilter.setFilters(Arrays.asList(new SessionRepositoryFilter((SessionRepository) applicationContext.getBean("sessionRepository")), applicationContext.getBean("myFilter")));

    return compositeFilter;
}

这解决了问题。

【讨论】:

    猜你喜欢
    • 2015-03-06
    • 2022-11-17
    • 2019-10-15
    • 2017-05-24
    • 2020-08-31
    • 2015-06-11
    • 2021-03-25
    • 2015-11-03
    • 2015-10-02
    相关资源
    最近更新 更多