REST后端的Spring Security CSRF保护 - 同步器令牌模式传输到客户端

问题描述:

我读了很多关于Spring Securitys CSRF保护的内容,但我仍然苦苦挣扎。现在的文档与往常一样好,但它完全基于您在服务器上呈现html代码并能够为每个表单添加隐藏字段的想法。现在,因为我使用AngularJS和JavaScript来调用后端,所以这不是一个真正的选择。REST后端的Spring Security CSRF保护 - 同步器令牌模式传输到客户端

那么在这种情况下实际获取Token给客户端的最佳方式是什么(Rest Backend/AngularJS前端)? AngularJS似乎已经在$ resource中构建了对CSRF的支持,并期望一个名为“XSRF-TOKEN”的Cookie来检索令牌,并在进一步请求中将其作为http头“X-XSRF-TOKEN”发送。所以每个请求都会包含http头以及cookie。现在在服务器端,我可以读取标题并将其与我存储在会话中的令牌进行比较。

我有这个问题,它似乎有点复杂。由于登录本身必须受到保护,因此需要创建一个临时会话,仅用于CSRF令牌。这真的有必要吗?

也许这只是一个愚蠢的问题,但为什么我不能在客户端创建一个随机标记并将其设置为客户端的HTTP标头和Cookie。这与“OWASP double submit cookie”类似,但在客户端生成令牌。这样服务器在登录前不需要进行会话,因为他可以比较两个提交的令牌。现在,虽然攻击者可以发送HTTP标头,但是根据同源策略,无法读取或设置cookie,只要数字几乎不可测,就无法获得匹配。

现在本能地在客户端生成一个安全的令牌对我来说似乎很危险,我想我会避免它..但为什么?我觉得我错过了一些东西,当然,SpringSecurity为什么在会话中存储令牌有一个很好的理由,对吧?

请赐教:)

+0

[如何访问Spring CSRF restful web服务](http://*.com/questions/33125598/how-to-access-spring-csrf-restful-web-service)可能有帮助吗? – holmis83

+0

2周前我已经解决了这个问题,但忘了在这里提到它。我现在发布了答案。虽然谢谢! –

我结束了使用spring-security-csrf-token-interceptor-extended,从HTTP头 “X-CSRF-TOKEN”(名称配置)读取CSRF令牌并且将其作为HTTP标头的进一步要求。

现在我唯一需要做的就是让Spring-Security发送Token作为HTTP Header(因为我不在服务器端渲染html代码,因此无法将其添加为隐藏字段)。

<security:http .... 
    <security:custom-filter ref="csrfTokenResponseHeaderBindingFilter" after="CSRF_FILTER"/> 
.... 
</security:http> 

滤波器正常CSRF_FILTER后基本上运行,并读取 “_csrf” 请求属性(其由CSRF_FILTER放在那里),并把它设定为标题 “X-CSRF-TOKEN”

public class CsrfTokenResponseHeaderBindingFilter extends OncePerRequestFilter { 
    protected static final String REQUEST_ATTRIBUTE_NAME = "_csrf"; 
    protected static final String RESPONSE_TOKEN_NAME = "X-CSRF-TOKEN"; 

    @Override 
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, javax.servlet.FilterChain filterChain) throws ServletException, IOException { 
     CsrfToken token = (CsrfToken) request.getAttribute(REQUEST_ATTRIBUTE_NAME); 

     if (token != null) { 
      response.setHeader(RESPONSE_TOKEN_NAME, token.getToken()); 
     } 

     filterChain.doFilter(request, response); 
    } 
}