跨源资源共享是一种机制,允许网页向另一个域发送xmlhttprequest(来自维基百科)。

在过去的几天里,我一直在摆弄CORS,我认为我对每件事情的工作原理都有很好的理解。

所以我的问题不是关于CORS /预飞是如何工作的,而是关于将预飞作为一种新的请求类型背后的原因。我看不出为什么服务器A需要发送一个preflight (PR)到服务器B,只是为了找出真实的请求(RR)是否会被接受——B当然有可能在没有任何预先PR的情况下接受/拒绝RR。

在搜索了相当多之后,我在www.w3.org(7.1.5)上找到了这条信息:

为了保护资源不受在本规范存在之前不能来自某些用户代理的跨源请求的影响,a 发出飞行前请求,以确保资源知道这一点 规范。

我发现这是最难理解的句子。我的解释(最好称之为“最佳猜测”)是关于保护服务器B不受服务器C的请求,因为服务器C不知道该规范。

谁能解释一个场景/展示一个PR + RR比RR单独解决更好的问题?


当前回答

下面是另一种看待它的方式,使用代码:

<!-- hypothetical exploit on evil.com -->
<!-- Targeting banking-website.example.com, which authenticates with a cookie -->
<script>
jQuery.ajax({
  method: "POST",
  url: "https://banking-website.example.com",
  data: JSON.stringify({
    sendMoneyTo: "Dr Evil",
    amount: 1000000
  }),
  contentType: "application/json",
  dataType: "json"
});
</script>

在cors之前,上述利用尝试将会失败,因为它违反了同源策略。以这种方式设计的API不需要XSRF保护,因为它受到浏览器本地安全模型的保护。cors之前的浏览器不可能生成跨源JSON POST。

现在CORS出现了——如果不需要通过飞行前选择加入CORS,突然之间这个网站就会有一个巨大的漏洞,这不是他们自己的过错。

为了解释为什么一些请求被允许跳过预飞行,这是在规范中回答的:

简单的跨源请求被定义为与这些请求一致 哪些可能是由当前部署的用户代理生成的 遵守这个规范。

为了解决这个问题,GET没有预先运行,因为它是7.1.5中定义的“简单方法”。(标题也必须“简单”,以避免预飞行)。 这样做的理由是,“简单的”跨源GET请求已经可以通过例如<script src="">来执行(这是JSONP的工作方式)。由于任何具有src属性的元素都可以触发跨源GET,没有预先飞行,因此在“简单”xhr上要求预先战斗将没有安全好处。

其他回答

下面是另一种看待它的方式,使用代码:

<!-- hypothetical exploit on evil.com -->
<!-- Targeting banking-website.example.com, which authenticates with a cookie -->
<script>
jQuery.ajax({
  method: "POST",
  url: "https://banking-website.example.com",
  data: JSON.stringify({
    sendMoneyTo: "Dr Evil",
    amount: 1000000
  }),
  contentType: "application/json",
  dataType: "json"
});
</script>

在cors之前,上述利用尝试将会失败,因为它违反了同源策略。以这种方式设计的API不需要XSRF保护,因为它受到浏览器本地安全模型的保护。cors之前的浏览器不可能生成跨源JSON POST。

现在CORS出现了——如果不需要通过飞行前选择加入CORS,突然之间这个网站就会有一个巨大的漏洞,这不是他们自己的过错。

为了解释为什么一些请求被允许跳过预飞行,这是在规范中回答的:

简单的跨源请求被定义为与这些请求一致 哪些可能是由当前部署的用户代理生成的 遵守这个规范。

为了解决这个问题,GET没有预先运行,因为它是7.1.5中定义的“简单方法”。(标题也必须“简单”,以避免预飞行)。 这样做的理由是,“简单的”跨源GET请求已经可以通过例如<script src="">来执行(这是JSONP的工作方式)。由于任何具有src属性的元素都可以触发跨源GET,没有预先飞行,因此在“简单”xhr上要求预先战斗将没有安全好处。

CORS允许您指定比以前cross-origin <img src>或<form action>更多的头文件和方法类型。

一些服务器可能已经(很差地)受到了浏览器无法做出的假设的保护,例如跨源DELETE请求或带有X-Requested-With头的跨源请求,因此这样的请求是“可信的”。

为了确保服务器真正支持CORS,而不是恰好响应随机请求,执行了preflight。

我花了一段时间对飞行前请求的目的感到困惑,但我想我现在明白了。

关键的观点是,飞行前请求不是一个安全问题。相反,它们是一种不改变规则的东西。

Preflight requests have nothing to do with security, and they have no bearing on applications that are being developed now, with an awareness of CORS. Rather, the preflight mechanism benefits servers that were developed without an awareness of CORS, and it functions as a sanity check between the client and the server that they are both CORS-aware. The developers of CORS felt that there were enough servers out there that were relying on the assumption that they would never receive, e.g. a cross-domain DELETE request that they invented the preflight mechanism to allow both sides to opt-in. They felt that the alternative, which would have been to simply enable the cross-domain calls, would have broken too many existing applications.

这里有三种场景:

Old servers, no longer under development, and developed before CORS. These servers may make assumptions that they'll never receive e.g. a cross-domain DELETE request. This scenario is the primary beneficiary of the preflight mechanism. Yes these services could already be abused by a malicious or non-conforming user agent (and CORS does nothing to change this), but in a world with CORS the preflight mechanism provides an extra 'sanity check' so that clients and servers don't break because the underlying rules of the web have changed. Servers that are still under development, but which contain a lot of old code and for which it's not feasible/desirable to audit all the old code to make sure it works properly in a cross-domain world. This scenario allows servers to progressively opt-in to CORS, e.g. by saying "Now I'll allow this particular header", "Now I'll allow this particular HTTP verb", "Now I'll allow cookies/auth information to be sent", etc. This scenario benefits from the preflight mechanism. New servers that are written with an awareness of CORS. According to standard security practices, the server has to protect its resources in the face of any incoming request -- servers can't trust clients to not do malicious things. This scenario doesn't benefit from the preflight mechanism: the preflight mechanism brings no additional security to a server that has properly protected its resources.

我觉得其他的答案并没有把重点放在战前提高安全性的原因上。

场景:

1) With pre-flight. An attacker forges a request from site dummy-forums.com while the user is authenticated to safe-bank.com If the Server does not check for the origin, and somehow has a flaw, the browser will issue a pre-flight request, OPTION method. The server knows none of that CORS that the browser is expecting as a response so the browser will not proceed (no harm whatsoever) 2) Without pre-flight. An attacker forges the request under the same scenario as above, the browser will issue the POST or PUT request right away, the server accepts it and might process it, this will potentially cause some harm.

如果攻击者直接从某个随机主机发送请求,那么很有可能是没有经过身份验证的请求。这是伪造的请求,但不是xsrf请求。服务器会检查凭证并失败。 CORS并不试图阻止拥有发出请求的凭据的攻击者,尽管白名单可以帮助减少这种攻击向量。

预飞行机制增加了客户端和服务器之间的安全性和一致性。 我不知道这是否值得为每个请求额外握手,因为缓存在那里是可以使用的,但这就是它的工作原理。

此外,对于HTTP请求方法可能导致的副作用 用户数据(特别是对于GET以外的HTTP方法或POST 使用特定的MIME类型),规范要求 浏览器“预先处理”请求