CSRF 和 X-CSRF-Token 的区别

Posted

技术标签:

【中文标题】CSRF 和 X-CSRF-Token 的区别【英文标题】:Difference between CSRF and X-CSRF-Token 【发布时间】:2016-04-19 08:38:42 【问题描述】: 在 HTTP 标头中使用 X-CSRF-Tokentoken 有什么区别 在隐藏的领域? 何时使用隐藏字段,何时使用标题,为什么?

我认为X-CSRF-Token 是我使用 javascript / AJAX 但我不确定的时候。

【问题讨论】:

【参考方案1】:

CSRF 保护有多种方法。

传统方式(the "Synchronizer token" pattern)通常涉及为每个请求设置唯一的有效 Token 值,然后在随后发送请求时验证该唯一值。通常通过设置隐藏表单字段来完成。令牌值通常是短暂的并且与该会话相关联,因此如果黑客试图重用他们之前在页面上看到的值,或者试图猜测值,他们很可能会失败。因此,只有来自您的应用程序的请求才会起作用,而来自您的应用程序/域外部的伪造请求(也称为跨站点请求伪造)将失败。

这样做的缺点是它要求您的应用程序在所有 html 表单上设置此隐藏标记。这些页面现在必须由应用程序动态生成,而以前它们可能是静态 HTML。它还可以破坏后退按钮(因为您需要刷新表单以重新生成另一个唯一的 CSRF 值)。您现在还需要跟踪服务器端的有效令牌并检查任何使用有效令牌的请求。这可能需要付出相当多的额外努力来实施和保持前进。

另一种方法(称为 the "Cookie-to-header token" pattern)是为每个会话设置一次 Cookie,然后让 JavaScript 读取该 cookie 并设置自定义 HTTP 标头(通常称为 X-CSRF-TOKENX-XSRF-TOKEN 或只是 XSRF-TOKEN)那个值。任何请求都将发送标头(由 Javascript 设置)和 cookie(由浏览器设置为标准 HTTP 标头),然后服务器可以检查 X-CSRF-TOKEN 标头中的值是否与 cookie 标头中的值匹配。想法是只有在同一域上运行的 JavaScript 才能访问 cookie,因此来自另一个域的 JavaScript 无法将此标头设置为正确的值(假设该页面不易受到 XSS 的攻击,从而可以访问此 cookie) .即使是虚假链接(例如在网络钓鱼电子邮件中)也不起作用,因为即使它们似乎来自正确的域,也只会设置 cookie 而不会设置 X-CSRF-TOKEN 标头。

这可能比同步器令牌模式更容易实现,因为您不需要为每个表单的每次调用设置令牌,并且检查也相对简单(只需检查 cookie 与标头匹配)而不是跟踪 CSRF 令牌的有效性。您只需为每个会话设置一个随机值的 cookie。一些前端框架甚至会在看到 cookie 时自动为您生成标头(例如,AngularJS does this)。

缺点是它需要 JavaScript 才能工作(但如果您的应用基本上在没有 JavaScript 的情况下无法工作,这可能不是问题)而且它仅适用于 JavaScript 发出的请求(例如 XHR 请求) - 常规HTML 表单请求不会设置标题。对此的一种变体("Double Submit Cookie" pattern)将X-CSRF-TOKEN 值放在隐藏的表单字段中,而不是放在 HTTP 标头中以解决此问题,但仍保持服务器端逻辑比传统的同步器令牌模式更简单。不过需要注意的是OWASP states some weaknesses with the Double Submit method,当攻击者能够设置 cookie(这通常比读取 cookie 更容易)时,因此建议在这种情况下验证 CSRF 令牌。

此外,同步器令牌模式可以允许额外的控制来强制执行流程(例如,隐藏字段 CSRF 令牌只会在应用程序认为您已发送有效请求以获取该表单时设置)。

哦,一些安全扫描会发现 cookie 没有设置 HTTP-Only 标志,因此可以被 JavaScript 读取 - 但这是故意的,因为它需要能够读取!虚假警报。您可能会认为,只要您使用像 X-CSRF-TOKEN 这样的通用名称,他们就会知道不标记这个,但经常看到它被标记。

【讨论】:

非常感谢您的解释。简而言之,`X-CSRF-TOKEN` 是针对 CSRF 的另一种保护措施,它更快,因为您可以通过 Javascript 设置它,并且它与 Form 中的隐藏文件同样安全。正确的?感谢您的宝贵时间 差不多。但它也有更多限制,因为您不能将其用于常规 HTML FORM 提交。 非常丰富的答案。谢谢!在 laravel 中 X-CSRF-TOKEN 与 CSRF 表单域完全一样。但是 X_XSRF_TOKEN 与 cookie 一起使用。 laravel.com/docs/5.4/csrf#csrf-x-xsrf-token【参考方案2】:

所有这些都用于跨站点请求伪造保护,在向后端发送请求时,您只需使用其中一个。不同的名称来自不同的框架。

这一切都是关于向后端发送csrf value。然后后端会将其与该特定用户存储在数据库中的 csrf 值进行比较。


csrf:

用于 HTML 表单(非 AJAX) 在渲染 HTML 表单时在后端生成。 我们不能直接在 HTML 表单中设置请求头,所以我们必须通过表单输入将其作为 隐藏字段发送。 您可以随意命名此隐藏输入。 例如:<input name="my_csrf_input" value="a_hashed_string(the csrf value)"

X-CSRF-TOKEN:

它被添加到 AJAX 请求的请求 HTTP 标头中。 要使用它,我们可以在渲染HTML时将csrf value放在<meta>标签中,然后在前端我们可以从<meta>标签中获取值并将其发送到后端。

特定于 Laravel:

使用Laravel 作为后端时。 Laravel 自动检查此标头并将其与数据库中的有效 csrf value 进行比较(Laravel 有一个中间件)。

X-XSRF-TOKEN:

它被添加到 AJAX 请求的请求 header 中。 AngularAxios 等流行库会自动从XSRF-TOKEN cookie 中获取此标头的值并将其放入每个请求标头中。 要使用它,我们应该在后端创建一个名为XSRF-TOKENcookie,然后我们使用Angular或Axios的前端框架会自动使用它。

特定于 Laravel:

因为它很受欢迎,Laravel 会在每个响应中创建这个 cookie。 因此,当您使用 Axios 和 Laravel 时,您无需执行任何操作,只需登录用户,“auth”中间件即可完成工作。 与 X-CSRF-Token 相比,它是一个更大的字符串,因为 cookie 在 Laravel 中是加密的。

【讨论】:

感谢您的解释。我正在使用 Laravel 和 React。对于获取,我使用 fetch API,而不是 Axios 或 XHR。最初,我不需要在 POST 请求标头中包含此 csrf 令牌。在本地主机中,它可以工作;但是当访问我部署在云中的应用程序时,每个 POST 请求都会失败。所以我想我需要包含 csrf 标头。如果是这样,哪一个: x-csrf-token 或 x-xsrf-token ?应该是后者吧? @LexSoft 是的,它在您的 cookie 中可用。您只需要从 cookie 中获取 x-xsrf-token 的值并随每个请求一起发送 感谢您的回复。我刚刚在 Laravel 文档中读到它提供了两个自定义标头以在 ajax 请求中使用。我会尝试两者。

以上是关于CSRF 和 X-CSRF-Token 的区别的主要内容,如果未能解决你的问题,请参考以下文章

HTTP 状态 403 - 在请求参数“_csrf”或标头“X-CSRF-TOKEN”上发现无效的 CSRF 令牌“null”

Laravel CSRF 中间件未检查 X-CSRF-TOKEN 请求标头

spring 如何使用 _csrf 参数或 X-CSRF-TOKEN 标头在内部验证 csrf 令牌?

在 Broadleaf 项目中 HTTP 状态 403 - 在请求参数“_csrf”或标头“X-CSRF-TOKEN”上发现无效的 CSRF 令牌“null”

使用fetchAPI和Drupal作为解耦后端的无效X-CSRF-Token请求标头

X-CSRF-TOKEN 不是 Spring Boot 生成的