REST 后端的 Spring Security CSRF 保护 - 将 Synchronizer Token Pattern 传输到客户端

Posted

技术标签:

【中文标题】REST 后端的 Spring Security CSRF 保护 - 将 Synchronizer Token Pattern 传输到客户端【英文标题】:Spring Security CSRF protection of REST backend - transfer Synchronizer Token Pattern to the client 【发布时间】:2016-08-13 00:12:04 【问题描述】:

我阅读了很多关于 Spring Securitys CSRF 保护的信息,但我仍然有点挣扎。现在文档和往常一样很棒,但它完全基于您在服务器上呈现 html 代码并能够为每个表单添加隐藏字段的想法。现在因为我使用 AngularJS 和 javascript 来调用后端,所以这不是一个真正的选择。

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

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

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

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

请赐教:)

【问题讨论】:

How to access Spring CSRF restful web service 可能有帮助吗? 我已经在两周前解决了这个问题,但是在这里忘记了。我现在发布了答案。不过谢谢! 【参考方案1】:

我最终使用了spring-security-csrf-token-interceptor-extended,它从 http-header "X-CSRF-TOKEN"(名称是可配置的)读取 CSRF-Token 并将其作为 http-header 发送给进一步的请求。

现在我唯一要做的就是让 Spring-Security 将令牌作为 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);
    

【讨论】:

以上是关于REST 后端的 Spring Security CSRF 保护 - 将 Synchronizer Token Pattern 传输到客户端的主要内容,如果未能解决你的问题,请参考以下文章

Spring Security:登录后如何重定向到 REST url

Springboot和Spring Security中认证成功后如何授权Rest API调用

使用 oauth2 在浏览器中登录后访问 REST 服务,使用 java config 访问 Spring Security

使用 Spring Security 保护 REST 端点

Spring Security + Angular App REST Token Based Authentication = 403 Forbidden on POST

如何使用 Spring Security 和 Angularjs 保护 Spring Rest 服务?