XMLHttpRequest
需要CORS跨域工作。同样适用于web字体、WebGL纹理和其他一些东西。一般来说,所有新的API似乎都有这个限制。
为什么?
它很容易规避:只需要一个简单的服务器端代理。换句话说,服务器端代码并没有被禁止进行跨域请求;为什么是客户端代码?这是如何为任何人提供安全保障的?
它是如此不一致:我不能XMLHttpRequest
,但我可以<script src>
、<link rel>
、<img src>
或<iframe>
。限制XHR等有什么作用?
如果我访问恶意网站,我想确保:
- 它无法从我使用的其他网站读取我的个人数据。想想attaker.com阅读gmail.com
- 它不能在我使用的其他网站上代表我执行操作。想想attacker.com从我在bank.com上的账户转账
同源政策解决了第一个问题。第二个问题被称为跨站点请求伪造,目前存在的跨域限制无法解决。
同源政策通常符合以下规则-
- 规则1:不允许您从其他域读取任何内容
- 规则2:允许您将想要的内容写入不同的域,但规则1不允许您读取响应
- 规则3:您可以自由地进行跨域GET请求和POST请求,但不能控制HTTP头
让我们看看你列出的各种东西是如何符合上述规则的:
-
<img>
标签允许您发出HTTP请求,但除了简单地显示图像之外,没有其他方法可以读取图像的内容。例如,如果我执行<img src="http://bank.com/get/latest/funds"/>
,请求将通过(规则2)。但是攻击者没有办法看到我的平衡(规则1)。 -
<script>
标签的工作原理与<img>
基本相同。如果您执行类似<script src="http://bank.com/get/latest/funds">
的操作,请求将通过。浏览器还会尝试将响应解析为JavaScript,但会失败。 -
众所周知,
<script>
标签被称为JSONP,您可以与跨域服务器串通,以便"读取"跨域。但是,如果没有跨域服务器的明确参与,您就无法通过<script>
标签读取响应 -
样式表的
<link>
的工作原理与<script>
标签基本相同,只是响应被评估为CSS。一般来说,您无法读取响应——除非响应碰巧是格式良好的CSS。 -
<iframe>
本质上是一个新的浏览器窗口。您无法读取跨域iframe的HTML。顺便说一句,您可以更改跨域iframe的URL,但无法读取该URL。注意它是如何遵循我上面提到的两条规则的。 -
XMLHttpRequest
是发出HTTP请求的最通用的方法。这完全由开发人员控制;浏览器对响应不做任何操作。例如,在<img>
、<script>
或<link>
的情况下,浏览器采用特定的格式,并且通常会对其进行适当的验证。但是在XHR中,没有规定响应格式。因此,浏览器强制执行同源策略,并阻止您读取响应,除非跨域网站明确允许。 -
通过
font-face
的字体是一种异常。AFAIK,只有Firefox需要选择加入行为;其他浏览器允许您像使用图像一样使用字体。
简而言之,同源政策是一致的。如果你想办法提出跨域请求,并且在未经跨域网站明确许可的情况下阅读响应,你将成为世界各地的头条新闻。
EDIT:为什么我不能用服务器端代理绕过这一切?
为了让gmail显示个性化数据,它需要来自浏览器的cookie。有些网站使用HTTP基本身份验证,其中凭据存储在浏览器中。
服务器端代理无法访问cookie或基本身份验证凭据。因此,即使它可以发出请求,服务器也不会返回用户特定的数据。
考虑这个场景。。。
- 你去我的恶意网站
- 我的网站向您的银行网站发送XHR,并要求提供银行转账表格
- XHR读取阻止CSRF的令牌,并将表单与安全令牌一起张贴,并将一笔钱转移到我的账户
- (I) 利润
如果没有同源策略,您仍然可以POST该表单,但您将无法请求阻止CSRF的CSRF令牌。
服务器端代码不在客户端的计算机上运行。
XHR的主要问题是,它们不仅可以发送请求,而且还可以读取响应。发送几乎任意的请求已经成为可能。但阅读他们的回复却并非如此。这就是为什么最初的XHR根本不允许任何跨源请求。
后来,当出现对XHR跨来源请求的需求时,CORS被建立起来,允许在特定条件下进行跨来源请求。一个条件是,特定的请求方法、请求头字段和将包含用户凭据的请求需要一个所谓的飞行前请求,客户端可以通过该请求检查服务器是否允许该请求。这样,服务器就可以限制对特定来源的访问,否则任何来源都可以发送请求。