【问题标题】:Spring Security CSRF protection of REST backend - transfer Synchronizer Token Pattern to the clientREST 后端的 Spring Security CSRF 保护 - 将 Synchronizer Token Pattern 传输到客户端
【发布时间】: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 将令牌存储在会话中肯定有充分的理由,对吧?

请赐教:)

【问题讨论】:

标签: angularjs spring-security csrf csrf-protection owasp


【解决方案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);
    }
}

【讨论】:

    猜你喜欢
    • 2016-11-12
    • 2016-03-04
    • 2019-06-17
    • 2016-01-12
    • 2014-07-12
    • 2020-09-05
    • 2019-07-13
    • 2019-06-19
    • 2012-10-22
    相关资源
    最近更新 更多