使用CORS Origin头与CSRF令牌进行CSRF保护

Chr*_*her 93 javascript security csrf cors

此问题仅针对防止跨站点请求伪造攻击.

具体来说:通过Origin头(CORS)保护和通过CSRF令牌保护一样好吗?

例:

所以:

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

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

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

注意:我不是在谈论

  • 原生应用,
  • 操纵浏览器,
  • example.com页面中的跨站点脚本错误,
  • ...

Sil*_*Fox 39

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

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

虽然之前存在浏览器漏洞,例如IE 5.5/6.0中的漏洞,攻击者可能会绕过同源策略并执行攻击,但您通常可以预期这些漏洞会在发现并且大多数浏览器自动更新时进行修补,这种风险将大部分得到缓解.

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

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

注意:我不是在谈论

  • 原生应用,

  • 操纵浏览器,

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

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


gue*_*est 27

Web内容无法篡改Origin标头.此外,在相同的原始策略下,一个来源甚至不能将自定义标头发送到其他来源.[1]

因此,检查Origin头与阻止攻击一样好,就像使用CSRF令牌一样.

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

浏览器供应商遵循这些规则,但插件呢?他们可能没有,但这个问题无视"被操纵的浏览器".如果浏览器中的bug让攻击者伪造Origin头?可能存在允许CSRF令牌在源头之间泄漏的错误,因此需要更多的工作来争辩一个比另一个好.

  • 我刚刚测试了Firefox 47并且它没有为跨源表单发送源头(一种攻击不为XHR启用CORS的REST服务的常用方法),所以我不认为原始头检查如果用户使用Firefox,则会有效. (5认同)
  • 作为参考,在Bugzilla上跟踪Firefox不发送"Origin"标题的问题:https://bugzilla.mozilla.org/show_bug.cgi?id = 446344在这种情况下您可以回退到检查"Referer"标题但是根据我的经验,一些Firefox用户因为隐私问题而阻止了"Referer"标题(尽管恕我直言,这将足以剥离路径和查询). (2认同)

Ada*_*dam 7

解释条款

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

GET 方法永远不会保存

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

<img src="https://dashboard.example.com/post-message/hello">
Run Code Online (Sandbox Code Playgroud)

响应是否为有效图像无关紧要 - 请求仍在执行。这就是为什么不能使用 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,因为它们无论如何都可以通过嵌入标签读取,如上所示。只要确保您没有状态改变获取方法)。