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

时间:2014-07-10 15:17:30

标签: javascript security cors csrf

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

具体说明:通过Origin头(CORS)的保护是否与通过CSRF令牌的保护一样好?

示例:

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

所以:

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

我知道,如果我们相信W3C规范在所有现代浏览器中都能正确实现(我们可以吗?)Security for cross-origin resource sharing)至少不能实现这一点。 >

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

注意:我不是在谈论

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

3 个答案:

答案 0 :(得分:37)

  

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

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

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

  

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

Origin标头通常仅针对XHR跨域请求发送。图像请求不包含标题。

  

注意:我不是在谈论

     
      
  • 原生应用程序,

  •   
  • 操纵浏览器,

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

  •   

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

答案 1 :(得分:27)

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

因此,检查Origin标头与使用CSRF标记阻止攻击一样好。

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

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

答案 2 :(得分:5)

解释术语

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

GET 方法永远不会保存

所有浏览器都实现了 same-origin policy。此策略通常避免域 A 上的 Web 应用程序可以向域 B 上的应用程序发出 HTTP 请求。但是,它不限制所有请求。例如同源策略是这样not restrict embed tags

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

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

飞行前检查

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

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

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

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

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

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

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