Rails API 应用程序的 CSRF 令牌

Har*_*ork 3 security ruby-on-rails csrf rails-api csrf-token

在 Rails API 应用程序中,我们没有现成的 CSRF 保护。特别是,不建议将访问令牌(例如 JWT)存储在 localStorage 中,建议存储在 cookie 中(带有 httpOnly 标志、SameSite 等)。但这一次我们很容易受到潜在的 CSRF 攻击。在全栈生成的 Rails 应用程序中,每次打开表单时都会生成并嵌入一个 CSRF 令牌。但是,我不知道也找不到任何我们如何在 Rails API 应用程序中使用令牌来防止 CSRF 的信息。我们有最佳实践吗?或者有人可以建议一种方法吗?我使用访问和刷新 JWT。

Gab*_*yel 6

这是 API 设计的常见权衡,您可以从几种具有不同风险状况的不同方法中进行选择。

您可以将访问令牌存储在 localStorage 或 sessionStorage 中,可供 javascript 访问,并接受风险。显然,风险主要集中在跨站脚本 (XSS) 方面,因为这样 javascript 就可以访问令牌,而在 XSS 的情况下,攻击者可以访问它,从而导致会话泄露。如果谈论 API,响应应将内容类型设置为application/json,这使得 API 本身在现代浏览器中免受 XSS 侵害。然而,这并不意味着客户端(大概是单页 JavaScript 应用程序)也受到保护,它很容易受到攻击并泄漏令牌。有些框架默认情况下可以更好地防御 XSS,有些则不然,您可能在 SDLC 中进行静态扫描等检查,为您提供一定程度的保证,让您可以接受这种风险。此外,如果您的 SPA 需要将令牌发送到多个源(不同的 api 端点),您实际上没有其他选择。在这种情况下,令牌可以作为请求标头发送,并且 CSRF 不是问题。

或者,您可以通过将令牌存储在 httpOnly cookie 中,将 XSS 换成 CSRF。这通常被认为更安全,因为 CSRF 通常是一个风险较低的漏洞(但仍然很重要)。在这种情况下,您将无法将令牌发送到不同的来源,但 XSS 也将无法访问。这并不能消除整个应用程序的 XSS,但至少令牌是安全的。代价是你现在必须处理 CSRF。一种方法是使用samesitecookies 属性。将其用于令牌 cookie 将防止大多数情况下的 CSRF,但这是一种用户体验权衡,某些浏览器的用户将不会受到保护,并且在使用lax选项时可能会错过某些情况samesite(例如当 GET 请求更改状态时)。由于上述原因,仅作为samesite保护也可能在渗透测试中被标记。

如果基于上述内容,您决定获得更多保护,则可以实现双重提交之类的功能,并仍然保持无状态,这是这些 API 很多时候的目标。在双重提交的情况下,您生成一个随机值,将其设置为 cookie(直接在客户端上,或通过服务器的响应),然后从请求标头中的 cookie 复制相同的值。服务器只需将 cookie 中的值与请求中的值进行比较,如果匹配,则请求正常。这样做的原因是因为攻击者在自己的域(源)上无法设置或读取受害者应用程序域的 cookie,这是由浏览器的同源策略确保的。

一种稍微不同的方法可能是应用根据整个请求和共享密钥(如 API 密钥)计算出的消息身份验证代码(如 HMAC),并在服务器上进行检查,但这是一种蠕虫病毒,很容易让HMAC 未涵盖的未受保护字段,服务器需要访问纯文本 api 密钥,以便可以计算 HMAC 等 - 要获得此权利并不简单)。

请注意,如果客户端应用程序容易受到 XSS 的攻击,则会否定任何 CSRF 保护,因为攻击者将有办法从客户端获取任何秘密,并使用任何计算字段(如有效令牌)执行任何请求。

  • 确实很好地总结了问题。我要更明确地提出几点 - httponly 减轻了与 XSS 相关的一些风险,但大多数风险仍然存在。即使攻击者无法读取 cookie,他们也可以在可以调用 API 的客户端应用程序的上下文中执行。他们将能够通过 XHR 使用凭据调用 API。此外,如果从客户端应用程序到 API 的合法请求是跨源的,则必须在 cookie 上设置“SameSite=none”。 (2认同)
  • 另一件事 - 对于跨域请求,CORS 策略将成为一个因素。确保所有改变状态的请求都经过预检将大大有助于防止 CSRF,因为“Access-Control-Allow-Origin”标头可以防止来自不受信任来源的突变。 (2认同)