引入飞行前请求的动机是什么?
引入了Preflight请求,以便浏览器在发送特定请求之前可以确定它正在处理一个支持cors的服务器。这些请求被定义为既具有潜在危险(状态改变)又具有新请求(由于同源政策,在CORS之前是不可能的)。使用飞行前请求意味着服务器必须选择(通过正确地响应飞行前请求)接受CORS使之成为可能的新的、具有潜在危险的请求类型。
这就是原始规范的这一部分的含义:“为了保护资源不受在此规范存在之前不能来自某些用户代理的跨起源请求的影响,发出预飞行请求以确保资源知道此规范。”
你能给我举个例子吗?
让我们假设一个浏览器用户登录到他们的银行网站A.com。当他们导航到恶意的B.com时,该页面包含一些试图向A.com/account发送DELETE请求的Javascript。由于用户登录到A.com,如果发送该请求,将包括识别用户的cookie。
在CORS之前,浏览器的同源策略会阻止它发送此请求。但由于CORS的目的是使这种跨起源通信成为可能,这已经不合适了。
浏览器可以简单地发送DELETE并让服务器决定如何处理它。但是如果。com不知道CORS协议怎么办?它可能会继续执行危险的DELETE。由于浏览器的同源策略(Same Origin policy),它可能认为它永远不会收到这样的请求,因此它可能从来没有对这样的攻击进行过加固。
为了保护这些不支持cors的服务器,该协议要求浏览器首先发送一个飞行前请求。这种新的请求只有支持cors的服务器才能正确响应,从而允许浏览器知道发送实际的DELETE是否安全。
为什么浏览器这么麻烦,攻击者就不能从他们自己的电脑发送一个DELETE请求吗?
当然,但是这样的请求不包括用户的cookie。这种设计用来防止的攻击依赖于这样一个事实:浏览器将在请求的同时为其他域发送cookie(特别是用户的身份验证信息)。
这听起来像是跨站请求伪造,即站点B.com上的表单可以用用户的cookie提交给A.com,并造成破坏。
这是正确的。另一种说法是,创建预飞行请求是为了不增加非cors感知服务器的CSRF攻击面。
但是POST被列为一种不需要预先操作的方法。它可以改变状态和删除数据,就像delete !
这是真的!CORS不能保护您的站点免受CSRF攻击。然而,如果没有CORS,您也无法免受CSRF攻击。飞行前请求的目的只是限制你的CSRF暴露在cors之前已经存在的世界。
叹息。好的,我勉强接受飞行前的要求。但是为什么我们必须对服务器上的每个资源(URL)都这样做呢?服务器要么处理CORS,要么不处理。
你确定吗?多个服务器处理单个域的请求并不罕见。例如,对A.com/url1的请求可能由一种服务器处理,而对A.com/url2的请求由另一种服务器处理。处理单个资源的服务器通常不能对该域中的所有资源提供安全保证。
好吧。让我们妥协。让我们创建一个新的CORS头,它允许服务器确切地声明它可以代表哪些资源,这样就可以避免对这些url的额外预飞行请求。
好主意!事实上,头文件Access-Control-Policy-Path正是为此目的而提出的。但最终,它被排除在规范之外,这显然是因为一些服务器错误地实现了URI规范,使得对浏览器来说似乎安全的路径的请求在损坏的服务器上实际上并不安全。
这是一个谨慎的决定,优先考虑安全性而不是性能,允许浏览器立即实现CORS规范,而不会使现有服务器处于危险之中?或者,仅仅为了在特定时间适应特定服务器上的漏洞,就注定要浪费互联网的带宽和加倍的延迟,这是短视的做法吗?
意见不同。
那么,至少浏览器会为单个URL缓存preflight ?
是的。虽然可能不会持续太久。在WebKit浏览器中,最大的预缓存时间目前是10分钟。
叹息。好吧,如果我知道我的服务器是cors感知的,因此不需要飞行前请求提供的保护,有什么方法可以避免它们吗?
您唯一的选择是确保您的请求使用cors安全的方法和头。这可能意味着省略您本来应该包含的自定义头文件(如X-Requested-With),更改Content-Type等等。
无论您做什么,都必须确保有适当的CSRF保护,因为CORS不会阻止所有不安全的请求。正如最初的规范所说:“对于那些简单的请求有意义而不是检索的资源,必须保护自己不受跨站点请求伪造的侵害”。