spring内部如何使用_csrf参数或X-CSRF-TOKEN header验证csrf token?

问题描述 投票:0回答:2

我正在使用 spring 并通过 HttpSessionCsrfTokenRepository 启用 csrf,我清楚地知道客户端是否将 csrf 令牌作为请求的 _csrf 参数或 X-CSRF-TOKEN 标头发送,spring 拾取令牌并使用使用生成的令牌进行验证

generateToken(HttpServletRequest request)
但我的问题是 spring 在内部是如何做到这一点的。 我提出这个问题的原因是:

1.我有一个 Rest POST 调用,它获取凭据并验证 用户的身份。但是因为我想添加一个 csrf 令牌 休息呼叫作为安全层我想将其添加到帖子正文中 以防止 csrf 令牌泄漏。

因此,如果我知道 spring security 如何在内部过滤这些令牌,那将会很有帮助。我修改了 spring 文档,但这主要是我们如何在带有隐藏字段或元标记的表单中使用 CSRF 令牌以及带有标头的 Ajax 调用。

我也想听到对我的设计的任何评论,如果将令牌放在正文中是好的(我确信它不是一个简单的 url 参数来泄漏令牌),或者我应该将它放在标题中。我只是不想仅仅因为它简单就倾向于使用 header 。寻找最佳解决方案。

请透露一些信息。

java spring spring-boot spring-security csrf
2个回答
4
投票

如果您想研究一下,Spring 中 CsrfTokenRepository 有多种实现。例如:

https://github.com/rwinch/spring-security/blob/master/web/src/main/java/org/springframework/security/web/csrf/HttpSessionCsrfTokenRepository.java

https://github.com/rwinch/spring-security/blob/master/web/src/main/java/org/springframework/security/web/csrf/CsrfFilter.java

https://github.com/rwinch/spring-security/tree/master/web/src/main/java/org/springframework/security/web/csrf

https://docs.spring.io/spring-security/site/docs/4.2.7.RELEASE/apidocs/org/springframework/security/web/csrf/CookieCsrfTokenRepository.html

https://docs.spring.io/spring-security/site/docs/4.2.7.RELEASE/apidocs/org/springframework/security/web/csrf/CookieCsrfTokenRepository.html

IMO 将令牌保留在标题上是件好事(可能更安全?),因为我能想到的原因很少..

  1. 您无法在 GET 请求的正文上设置令牌。您希望所有端点保持一致(您今天可能不需要它,但事情变化得很快)

  2. 明天如果您想更改您的身份验证模型,您不想更改您的请求正文。当请求正文发生更改时,您就违反了与客户的合同

  3. 如果您将身份验证模型更改为授权服务器,您可以在服务之前添加代理服务器(例如ngnix?),我们将其称为身份验证代理。您可以将所有与安全相关的事情留给此身份验证代理,它会检查标头并为您进行验证。您不希望代理查看您的请求正文,您可以专注于您的业务实现

  4. 请求正文与您的业务完全相关,因此您可以专注于它,而不是处理正文中与安全相关的事情。
  5. 每次为新端点创建新请求时,您不希望在所有请求中继续添加令牌

这只是我根据我的经验得出的意见。


0
投票

注意:此信息适用于

Spring Security 6
,但旧版本也可能相同。

现在,让我们开始吧。

  • 首先,我们有一个由两个类实现的
    CsrfTokenRepository
    接口:
    CookieCsrfTokenRepository
    HttpSessionCsrfTokenRepository
  • 考虑到我们正在使用基于cookie的CSRF令牌。为此,将使用
    CookieCsrfTokenRepository
  • 在内部,将调用方法
    loadToken(HttpServletRequest request)
    从请求收到的cookie中提取令牌。 (loadToken方法在
    RepositoryDeferredCsrfToken
    类中)
  • 如果从 cookie 中找到 CSRF 令牌,则会创建
    DefaultCsrfToken
    的对象。 (
    new DefaultCsrfToken(this.headerName, this.parameterName, token)
    )
  • 现在,实际的验证部分位于
    CsrfFilter
    类中。
  • requestHandler.resolveCsrfTokenValue(request, csrfToken)
    方法从标头/参数中提取CSRF令牌。 (方法如下)
@Override
default String resolveCsrfTokenValue(HttpServletRequest request, CsrfToken csrfToken) {
    Assert.notNull(request, "request cannot be null");
    Assert.notNull(csrfToken, "csrfToken cannot be null");
    String actualToken = request.getHeader(csrfToken.getHeaderName());
    if (actualToken == null) {
        actualToken = request.getParameter(csrfToken.getParameterName());
    }
    return actualToken;
}
  • 因此,将从 cookie 中提取的一个 CSRF 令牌与从标头/参数中提取的另一个 CSRF 令牌进行比较,并做出相应的决定。
  • 如果它们相等,那么 woohoo :) 否则,会照常返回
    403 forbidden
    状态 :(
© www.soinside.com 2019 - 2024. All rights reserved.