使用 CORS Origin 标头与 CSRF 令牌的 CSRF 保护

IT技术 javascript security cors csrf
2021-03-18 11:06:22

这个问题仅与防止跨站点请求伪造攻击有关。

它具体是关于:通过 Origin 标头 (CORS) 进行的保护是否与通过 CSRF 令牌进行的保护一样好?

例子:

  • Alice 使用她的浏览器登录(使用 cookie)到“ https://example.com ”。我假设,她使用的是现代浏览器。
  • Alice 访问“ https://evil.com ”,evil.com 的客户端代码对“ https://example.com执行某种请求(经典的CSRF 场景)。

所以:

  • 如果我们不检查 Origin 标头(服务器端),并且没有 CSRF 令牌,我们就有一个 CSRF 安全漏洞。
  • 如果我们检查 CSRF 令牌,我们是安全的(但有点乏味)。
  • 如果我们确实检查了 Origin 标头,那么应该像使用 CSRF 令牌时一样阻止来自 evil.com 的客户端代码的请求——除非有可能让 evil.com 的代码以某种方式设置 Origin 标头。

我知道,这对于 XHR 来说是不可能的(参见例如跨域资源共享的安全性),至少不会,如果我们相信 W3C 规范在所有现代浏览器中都能正确实现(我们可以吗?)

但是其他类型的请求呢——例如表单提交?加载 script/img/... 标签?或者页面可以用来(合法地)创建请求的任何其他方式?或者也许是一些已知的 JS hack?

注意:我不是在谈论

  • 本机应用程序,
  • 被操纵的浏览器,
  • example.com 页面中的跨站点脚本错误,
  • ...
3个回答

知道,这不应该用 XHR 实现(参见例如跨域资源共享的安全性),至少不是,如果我们相信 W3C 规范在所有现代浏览器中都能正确实现(我们可以吗?)

在一天结束时,您必须“信任”客户端浏览器以安全地存储用户数据并保护会话的客户端。如果您不信任客户端浏览器,那么您应该完全停止使用 Web 来获取静态内容以外的任何内容。即使使用 CSRF 令牌,您也相信客户端浏览器会正确遵守同源策略

虽然之前存在浏览器漏洞,例如IE 5.5/6.0中的漏洞,攻击者可能会绕过同源策略并执行攻击,但您通常可以期望这些漏洞在发现后立即修复,并且大多数浏览器会自动更新,这种风险将在很大程度上得到缓解。

但是其他类型的请求呢——例如表单提交?加载 script/img/... 标签?或者页面可以用来(合法地)创建请求的任何其他方式?或者也许是一些已知的 JS hack?

Origin报头通常只用于发送XHR跨域请求。图像请求不包含标头。

注意:我不是在谈论

  • 本机应用程序,

  • 被操纵的浏览器,

  • example.com 页面中的跨站点脚本错误,

我不确定这是否属于受操纵的浏览器,但旧版本的 Flash允许设置任意标头,这将使攻击者能够referer从受害者的机器发送带有欺骗标头的请求以执行攻击。

@ChrisLercher:是的,现代插件似乎更强大一些。但是,随时可能发布新版本,允许攻击者以绕过浏览器保护的方式利用它。处理它的最佳方式(例如令牌/标头)将取决于您的数据的敏感性以及此类风险是否可以接受。Flash 确实遵守 SOP,但 Flash 插件的来源是它加载的站点(而不是像 JavaScript 那样的调用站点)。有一个crossdomain.xml可以实现跨域通信。
2021-05-08 11:06:22
Flash 示例是一个很好的示例——也许其他插件可能也有类似的漏洞。我(不幸的是)只能保护 Alice 免受 CSRF 的影响,如果她使用现代浏览器等,这很清楚。但并非没有道理,即使作为具有安全意识的用户,她也可能安装了 3rd 方插件——尤其是当它们来自大型(值得信赖的)公司时。即使他们可能会编写安全的插件,我也不是 100% 相信,如果他们也考虑 CSRF!因此,除非浏览器沙箱限制插件违反 SOP(他们可能吗?),否则我宁愿建议坚持使用 CSRF 令牌。
2021-05-19 11:06:22

Web 内容不能篡改 Origin 标头。此外,在同源策略下,一个源甚至不能向其他源发送自定义标头。[1]

因此,检查 Origin 标头与使用 CSRF 令牌一样擅长阻止攻击

依赖于此的主要问题是它是否允许所有合法请求工作。提问者知道这个问题,并设置了问题以排除主要情况(没有旧浏览器,仅限 HTTPS)。

浏览器供应商遵循这些规则,但插件呢?他们可能不会,但这个问题忽略了“被操纵的浏览器”。浏览器中让攻击者伪造 Origin 标头的错误怎么办?也可能存在允许 CSRF 令牌跨源泄漏的错误,因此需要更多的工作来论证一个比另一个更好。

作为参考,在 Bugzilla 跟踪了 Firefox 未发送“Origin”标头的问题:bugzilla.mozilla.org/show_bug.cgi ?id=446344 在这种情况下,您可以回退到检查“Referer”标头,但根据我的经验,有些由于隐私问题,Firefox 用户阻止了“Referer”标头(尽管恕我直言,剥离路径和查询就足够了)。
2021-04-24 11:06:22
我刚刚测试了 Firefox 47,它没有发送跨域表单帖子的源头(攻击不为 XHR 启用 CORS 的 REST 服务的常见方法),所以我不认为源头检查如果用户使用 Firefox,这将是有效的。
2021-05-07 11:06:22

解释条款

我认为问题应该是同源策略 vs CSRF token因为CORS是一种允许两个不同域相互交谈的机制(通过放宽同源策略),而同源策略CSRF令牌限制域相互交谈。

GET 方法永远不会保存

所有浏览器都实现同源策略此策略通常避免域 A 上的 Web 应用程序可以向域 B 上的应用程序发出 HTTP 请求。但是,它不限制所有请求。例如同源策略不限制嵌入标签是这样的:

<img src="https://dashboard.example.com/post-message/hello">

响应是否为有效图像无关紧要——请求仍会被执行。这就是为什么不能使用 GET 方法调用 Web 应用程序上的状态更改端点很重要的原因。

飞行前检查

您可以使用CORS来避免同源策略,并让域 A 向域 B 发出否则将被禁止的请求。在实际请求发送之前,将发送预检请求以检查服务器是否允许域 A 发送此请求类型。如果是,域 A 将发送原始请求。

例如,如果未设置 CORS,则预检将限制域 A 的 Javascript XMLHttpRequests,而不会在域 B 上执行请求。

为什么尽管同源策略仍需要 CSRF 令牌

如果同源策略适用于所有类型的请求,那么您是对的并且不需要使用 CSRF 令牌,因为您将受到同源策略的全面保护。然而,这种情况并非如此。有几个 HTTP 请求不发送预检请求!

具有特定标头和特定内容类型的 GET、HEAD 和 POST 请求不会发送预检请求。此类请求称为简单请求这意味着请求将被执行,如果请求不被允许,则将返回一个不允许的错误响应。但问题是,简单的请求是在服务器上执行的。

不幸的是,一个平原<form action="POST">创建了一个简单的请求!

由于这些简单的请求,我们必须使用 CSRF 令牌保护 POST 路由(GET 路由不需要 CSRF,因为它们无论如何都可以通过嵌入标签读取,如上所示。只要确保您没有状态改变获取方法)。