跨站请求伪造 (CSRF) 防御

跨站请求伪造 (CSRF) 可以通过 SameSite Cookie 和反 CSRF 令牌进行防御。

问题

CSRF 是一种攻击类型,攻击者会通过可信用户向网站发送未经授权的命令。由于它们继承了用户的 Cookie(因此也继承了会话信息),因此它们看起来是有效的命令。CSRF 攻击可能如下所示

html
<!-- Attempt to delete a user's account -->
<img src="https://accounts.example.org/management/delete?confirm=true" />

当用户访问包含上述 HTML 的页面时,浏览器将尝试向源 URL 发出 GET 请求。如果用户已登录,浏览器将提供其会话 Cookie,并且帐户删除尝试将成功。

解决方案

有多种 CSRF 缓解策略可用。最常见且最透明的 CSRF 缓解方法是 SameSite Cookie 和反 CSRF 令牌。

注意:跨站脚本 (XSS) 漏洞可能会克服您实施的任何 CSRF 缓解技术。确保同时针对这两种攻击类型强化您的网站。可以使用 内容安全策略 (CSP) 等功能来防止 XSS。

SameSite Cookie

SameSite Cookie 允许您指定您希望浏览器仅在响应来自 Cookie 源站点的请求时才发送 Cookie。例如,这将导致 CSRF 攻击失败,因为恶意命令不会附带 Cookie,因此无法以用户身份进行身份验证。可用的值是

严格

导致浏览器仅在响应来自 Cookie 源站点的请求时才发送 Cookie。

宽松

严格 相似,只是浏览器还会在用户导航到 Cookie 的源站点时发送 Cookie(即使用户来自不同的站点)。

指定在源请求和跨站点请求中都发送 Cookie。

您应该为您的网站设置尽可能强大的 SameSite 级别,以使其仍然有效。理想情况下,除非您确实需要,否则永远不要设置 。请记住,如果未指定标头,则 宽松 是默认值。

反 CSRF 令牌

反 CSRF 令牌通过要求在所有破坏性更改中都存在一个秘密、唯一且不可预测的令牌来防止 CSRF 攻击。这些令牌可以为整个用户会话设置,定期轮换,或者为每个请求唯一创建。

建议您为允许破坏性更改(如帐户删除)的网站使用这两种策略。对于其他网站,反 CSRF 令牌可能不是必需的,尽管仍然建议将 SameSite 设置为非 值,以帮助保护用户的 隐私

大多数应用程序框架都内置了 CSRF 令牌化功能,以简化实施。请务必选择一个具有此功能的框架,不要试图重新造轮子。

示例

实施反 CSRF 令牌以及 SameSite=严格

在帐户删除表单中包含一个秘密的反 CSRF 令牌

html
<input
  type="hidden"
  name="csrftoken"
  value="1df93e1eafa42012f9a8aff062eeb1db0380b" />

在服务器端,设置反 CSRF Cookie(JavaScript 必须将其发送为 X 标头;它无法跨源执行)

http
Set-Cookie: CSRFTOKEN=1df93e1eafa42012f9a8aff062eeb1db0380b; Path=/; Secure; SameSite=Strict

回到客户端,使用 JavaScript 将 CSRF 令牌作为 X 标头添加到 XMLHttpRequest

js
const token = readCookie(CSRFTOKEN); // read the cookie
httpRequest.setRequestHeader("X-CSRF-Token", token); // add it as an X-CSRF-Token header

另请参阅