XMLHttpRequest同源策略

12

我最近三天一直在学习如何使用XMLHttpRequest来进行跨域请求。目前最好的替代方法是JSONP,而我已经在使用了。

但是,我还有一个问题,在许多帖子(包括stackoverflow)中阅读了数百篇文章,没有人提供好的、可靠的答案(并带有良好的参考资料)。希望这里能有人能够帮助我。

话虽如此,我在许多网站上读到由于安全原因,我不能从 aaa.com 域向 bbb.com 进行Ajax请求并获取我想要的数据。这很清楚,我对此也没有疑问。但是,当我在本地主机上运行下面的代码时(所以我的域名是“localhost”,我不应该能够从另一个域请求任何数据),问题就出现了。

xhReq = new XMLHttpRequest();
xhReq.open("GET","http://domain.com?parameter",true);
xhReq.send(null);

当我检查Firebug Net标签时,我意识到请求并没有被阻塞!它明显被请求了。我简直不敢相信。所以我在domain.com/log.php中创建了一个文件,我可以记录任何访问我的域名的请求。令人惊讶地是,我发送到localhost的所有请求都会命中我的domain.com。当我尝试获取响应时,由于Chrome和Firebug浏览器的同源策略,我确实无法获得响应。但我真的很惊讶,因为请求确实命中了Web服务器,尽管我无法操作响应。

更令人惊讶的是,如果domain.com/log.php生成一个巨大的响应,例如1MB,我的Firebug会显示浏览器从Web服务器下载了全部1MB,并在最后显示“Access denied”消息,正如预期的那样。那么,如果同源策略禁止读取数据,为什么下载整个文件呢?

最后,让我感到惊讶的是,我阅读的所有网站和规范都非常明确地说,当目标域与源域不匹配时,Ajax会阻止请求。但是,通过我的实验,很明显请求已经完成了,尽管我无法访问响应数据。

让我不安的是,这可能会打开一个巨大的安全漏洞,一个每天有数千次浏览量的网站可以运行这3行代码,并在小间隔中使用户请求其他网站的页面,因为浏览器不会阻止请求。

我在IE 7、8和9以及最新版本的Chrome和Firefox中测试了这个脚本,行为都是相同的:请求已完成,浏览器下载了所有响应,但没有使其对SOP可用。

希望有人能解释一下为什么规范这么错误或者我理解错了什么!


好问题。不知道为什么请求会命中外部域。我在这里进行了测试,和你一样,请求已经完成,但是我无法获取响应。希望有人能帮忙。 - amandanovaes
你能检查一下 domain.com 是否已启用了CORS,但如果启用了,IE应该无法使用... 无论如何,你能确认一下吗? - Arun P Johny
@ArunPJohny 不,CORS 没有启用。这只是一个示例网站。您可以将 domain.com 更改为任何域名,然后在 Firebug 或 Chrome Net 控制台中查看请求已完成且没有错误。很明显这不是一个 bug,因为我测试的所有浏览器都表现出相同的行为,但是为什么规范会说跨域 ajax 请求 "被阻止" 呢? - Samul
1
我只想让你知道,我花了最近几个小时进行了多次测试,所有的情况下请求都成功并且连上了服务器!真的很奇怪!感谢你发布这个问题。 - amandanovaes
2个回答

3

请参见类似问题中的bobince's answer:

根据XMLHttpRequest 2级,浏览器允许发送跨域GET请求而无需进行预检,但不允许从响应中读取结果,除非远程域选择加入。这里没有额外的漏洞,因为您已经可以通过多个更基本的接口导致对任意URL的GET请求(包括查询字符串)。

例如,您一直可以创建一个元素,其src设置为远程域上的地址;取消该跨域功能将破坏现有Web的很多内容。

相关:


这里没有额外的漏洞......我在想。我知道跨域GET需要与IMG、IFRAME和SCRIPT标签一起使用。但是它需要从脚本内部即XmlHttpRequest中工作吗?如果不需要,似乎这给黑客更多的权力。我在想,也许更好的方法是浏览器使用HEAD来获取凭据。 - Panu Logic

3
这是因为客户端(浏览器)会应用相同的源策略,通过评估服务器返回的以下访问控制头值:
  • Access-Control-Allow-Origin
  • Access-Control-Allow-Methods
  • Access-Control-Allow-Headers
如您所见,必须先在服务器上完成请求,以便浏览器检查返回的标头。这正是您的请求在服务器上执行的原因。
您可以查看A. Barth的同源策略原则

根据问题“浏览器确实会下载全部1MB”。因此,我想知道浏览器是否真的需要下载所有内容,因为响应应该以头开始,告诉它不要下载这个。 - Panu Logic

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接