CORS-引入飞行前要求的动机是什么?

跨域资源共享是一种允许网页向另一个域(来自Wikipedia发出XMLHttpRequests的机制

在过去的几天里,我一直在摆弄CORS,我认为我对所有工作原理都非常了解。

因此,我的问题不是关于CORS /预检如何工作,而是关于将预检作为新的请求类型的原因我看不到任何原因,为什么服务器A需要向服务器B发送预检(PR)只是为了确定是否接受实际请求(RR)-B肯定有可能在没有请求的情况下接受/拒绝RR任何先前的PR。

经过大量搜索后,我在www.w3.org(7.1.5)上找到了以下信息:

为了保护资源免受在该规范存在之前可能源自某些用户代理的跨域请求,将进行预检请求以确保资源了解此规范。

我发现这是有史以来最难理解的句子。我的解释(最好将其称为“最佳猜测”)是关于保护服务器B免受来自服务器C的不知道该规范的请求的影响。

有人可以解释一个情况/显示PR + RR比单独使用RR更好地解决问题吗?

LEYMandy猿2020/03/23 15:15:37

此外,对于可能对用户数据产生副作用的 HTTP请求方法(特别是对于GET以外的HTTP方法或某些MIME类型的POST使用),规范要求浏览器“预检”请求

资源

伽罗2020/03/23 15:15:37

在支持CORS的浏览器中,读取请求(如GET)已经受到同源策略的保护:试图发出经过身份验证的跨域请求(例如,到受害者的网上银行网站或路由器的配置界面)的恶意网站不会能够读取返回的数据,因为存储区或路由器未设置Access-Control-Allow-Origin标头。

但是,通过写入请求(如POST),当请求到达Web服务器时会造成损害。* Web服务器可以检查Origin标头以确定请求是否合法,但是由于其中一个Web服务器都不需要,因此通常不执行此检查适用于CORS或Web服务器的版本早于CORS,因此假设同源规则完全禁止跨域POST。

这就是为什么让网络服务器有机会选择接收跨域写请求

*本质上是CSRF的AJAX版本。

村村2020/03/23 15:15:37

关于性能的预先要求不是吗?使用预检请求,客户端可以在发送大量数据之前快速了解是否允许该操作,例如,使用JSON和PUT方法。或在通过身份验证标头传输敏感数据之前。

默认情况下,除自定义标头外,不允许PUT,DELETE和其他方法的事实(它们需要“ Access-Control-Request-Methods”和“ Access-Control-Request-Headers”的显式许可),听起来就像仔细检查一样,因为这些操作可能会对用户数据(而不是GET请求)产生更多影响。因此,听起来像:

“我看到您允许来自http://foo.example的跨站点请求,但是您确定要允许DELETE请求吗?您是否考虑过这些请求可能对用户数据造成的影响?”

我不明白预检请求和旧服务器收益之间所引用的相关性。在CORS之前实施的Web服务或没有CORS意识的Web服务将永远不会收到任何跨站点请求,因为首先它们的响应将没有“ Access-Control-Allow-Origin”标头。

阳光猿2020/03/23 15:15:36

考虑CORS之前的跨域请求的世界。您可以执行标准形式的POST,也可以使用scriptimage标记发出GET请求。除了GET / POST之外,您不能发出任何其他请求类型,并且不能在这些请求上发出任何自定义标头。

随着CORS的到来,规范作者面临着在不破坏Web现有语义的情况下引入新的跨域机制的挑战。他们选择通过为服务器提供选择加入任何新请求类型的方式来做到这一点。选择加入是预检请求。

因此,没有任何自定义标头的GET / POST请求不需要进行预检,因为这些请求在CORS之前就已经可以实现。但是,任何带有自定义标头的请求或PUT / DELETE请求需要进行预检,因为这些对CORS规范来说是新的。如果服务器对CORS一无所知,它将在没有任何CORS特定标头的情况下进行回复,并且不会发出实际请求。

如果没有预检请求,服务器可能开始看到来自浏览器的意外请求。如果服务器没有为这些类型的请求做好准备,则可能导致安全问题。CORS预检允许以安全的方式将跨域请求引入Web。

村村Itachi2020/03/23 15:15:36

这是使用代码的另一种查看方式:

<!-- 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进行预检查不会带来安全性好处。

神乐西里2020/03/23 15:15:36

我觉得其他的答案不是集中在预战提高安全性的原因上。

场景:

1)飞行前在用户通过safe-bank.com身份验证时,攻击者伪造了来自dummy-forums.com网站的请求。
如果服务器未检查来源,并且以某种方式存在缺陷,浏览器将发出飞行前请求OPTION方法。服务器不知道浏览器期望将其作为响应,因此浏览器将不会继续运行(不会造成任何危害)

2)没有预检攻击者在与上述相同的情况下伪造该请求,浏览器将立即发出POST或PUT请求,服务器会接受并可能处理该请求,这可能会造成一些危害。

如果攻击者从某个随机主机跨源直接发送请求,则很可能是考虑没有身份验证的请求这是伪造的请求,但不是xsrf请求。因此,服务器将检查凭据并失败。尽管白名单可以帮助减少这种攻击媒介,但是CORS不会尝试阻止具有发出请求凭据的攻击者。

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

梅猿2020/03/23 15:15:36

CORS可以让你比跨域以前可能指定更多的头部和方法类型<img src><form action>

假设浏览器无法进行某些服务器的保护(差),例如跨域DELETE请求或带有X-Requested-With标头的跨域请求,因此此类请求是“受信任的”。

为了确保服务器真正支持CORS,而不仅仅是偶然响应随机请求,将执行预检。