如何将 CSRF 令牌共享给客户端应用程序?

信息安全 csrf
2021-09-11 03:21:02

我有两个不同的网络应用程序。服务 Web 应用程序定义了 REST 服务。客户端 Web 应用程序具有 JSP 页面,这些页面使用 Ajax 调用 REST 服务以获取数据并在 UI 中显示。我想为我的 REST 服务实现 OWASP CSRF Gaurd 3。

如何在客户端应用程序中获取 CSRF 令牌值,以便它可以将令牌值作为标头传递,其余服务得到验证和执行?

让我清楚地告诉我我的架构。服务项目 - 这是一个定义了 REST Web 服务的 spring/JPA 项目。该项目需要使用 CSRF 进行保护。它的 Web 上下文是 /Services。所以 url 可能在 localhost 中http://localhost:8080/Services/RESTSERVICE

客户端项目 - 这是一个带有 jsp/html 网页的 JSP/Servlet 项目。该项目对服务项目的 REST 服务进行 AJAX 调用,以获取数据并在 UI 中显示。网址就像http://localhost:8080/Client/index.jsp

现在我怀疑如果我在服务项目中实现 CSRF Guard,客户端项目需要 CSRF 令牌来调用受保护的 REST 服务。如何将此令牌值获取到客户端项目 jsp 页面中?

我尝试将 cookie 添加到其余服务的响应中,但客户端 javascript 无法读取它,因此使用 cookie 我无法将令牌共​​享给客户端。还有其他方法吗?任何帮助将不胜感激...

4个回答

只需实现一个/token端点,端点在给定会话 cookie 的情况下提供 CSRF 令牌。请记住,只要不同域上的客户端 JS 无法获取使用它来构造请求(大多数客户端 JS 可以做的是在隔离的 iframe 中显示它),CSRF 是不可能的。如果域不同,则允许客户端应用通过 CORS 获取令牌。

我最近不得不这样做并最终将 CSRF 令牌放入全局 javascript 变量中。然后,当我打电话时,我会将此标记作为参数包含在内。由于攻击者无法从您的浏览器读取任何状态,因此它应该是安全的。

例子:

$.ajax({
  type: "POST",
  url: "some.php",
  data: { name: "John", location: "Boston", _csrf: _GLOBALS._csrf }
});

我遇到了同样的问题,并决定使用“一次性令牌请求”。像这样的东西:

  1. 输入登录密码,认证,授权,加载项目主页面
  2. /csrf-token在任何其他请求之前调用方法,例如在初始引导阶段
    • 服务器生成令牌,然后在服务器会话数据中的某处记下,已经请求了 csrf 令牌,因此所有未来的调用都/csrf-token将失败。
  3. 客户记住该令牌并将其用于所有未来的请求;例如,它可以在某些 javascript 命名空间中记住它,因此只能从该页面/选项卡访问它。

这种方法的主要缺点:例如,如果您重新加载页面,则必须签名。

在客户端添加 CSRF Token

pom.xml:

<dependency>
    <groupId>org.webjars</groupId>
    <artifactId>js-cookie</artifactId>
    <version>2.1.0</version>
</dependency>

以 HTML 格式导入:

<script type="text/javascript" src="/webjars/js-cookie/js.cookie.js"></script>

那么我们可以在 xhr 中使用 Cookies 便捷方法:

$.ajaxSetup({
beforeSend : function(xhr, settings) {    
      xhr.setRequestHeader("X-XSRF-TOKEN",
          Cookies.get('XSRF-TOKEN'));
    }
  }
}
});

来源:https ://spring.io/guides/tutorials/spring-boot-oauth2/