为什么需要跨域?
因为有同源策略。
同源策略是一种非常重要的安全机制,约束(限制)一个源的文档或者脚本如何与另一个源的资源进行交互。有助于隔离恶意文档,减少可能的攻击。
源
如果两个URL具有相同的protocol,相同的port(如果有)以及相同的host,就说它们具有相同的源
如下表格是与如下URL对比的结果:http://store.company.com/dir/page.html
:
IE浏览器的例外
- 可信任区:如果两个域都处于高度可信任区(企业内部网),将不会有同源限制。
- 端口:IE在检查于时并不考虑port。下面两个URL被当做同源:
https://company.com:81/index.html
和https://company.com/index.html
改变源
虽然有一定限制,页面可以通过document.domain来改变自己源。可以通过脚本修改document.domain到自身当前的域或者当前域的超域。
例如,在http://store.company.com/dir/other.html
运行如下脚本:
document.domain = "company.com"
之后,这个页面就可以通过http://company.com/dir/page.html
页面的同源检查。
但是,company.com不能够修改document.domain到othercompany.com,因为它不是company.com的超域。
跨域访问方法
同源策略限制了不同源之间的交互,比如使用XMLHttpRequest和<img>。这些交互可以大致分为三类:
- 被允许的跨域写操作。例如链接、重定向和表单提交。一些HTTP请求需要preflight。
- 嵌入式的跨域操作
- 跨域读操作通常不被允许,但是读操作经常可以通过嵌入式实现。例如,可以读取嵌入图片的大小,读取嵌入脚本的行为,或者嵌入资源的可用性。
以下是可以嵌入跨域的资源示例:
- javascript的<script src="..."></script>,但是语法错误等细节依然只能同源脚本访问;
- 引入css的<link rel="stylesheet" href="...">
- 嵌入图片的<img>
- 多媒体标签<video>和<audio>
- 插件标签<object><embed><applet>
- 字体相关的@font-face,只有部分浏览器支持跨域字体
- <frame><iframe>,网站可以使用X-Frame-Options首部阻止跨域
如何允许跨域访问
使用CORS(cross-origin resource sharing)。CORS背后的思想是:使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或者响应是应该成功还是失败。
如何阻止跨域访问
- 为了防止跨源写操作,请检查请求中不可猜测的令牌—称为跨站点请求伪造(CSRF)令牌。必须防止需要此标记的页面的跨源读取。
- 要防止资源的跨源读取,请确保资源不可嵌入。通常有必要防止嵌入,因为嵌入一个资源总是会泄露一些关于它的信息
- 要防止跨域嵌入,确保你的资源不是上面列出的嵌入操作之一。浏览器可能不会遵守Content-Type首部。例如,如果将<script>标记指向HTML文档,浏览器将尝试将HTML解析为JavaScript。当资源不是站点的入口点时,还可以使用CSRF令牌来防止嵌入。
可以跨域的API
iframe.contentWindow,window.parent,window.open和window.opener这些javascript的API,允许文档之间互相引用。当两个文档不属于相同的域,这些引用提供了对于Window和Location的有限访问,就像下面两个小节所描述的。
两个不同域的文档可以使用window.postMessage进行通信。
window
允许对窗口进行下列的跨域属性的访问
Location
允许对location的以下属性进行跨域访问
跨域数据存储访问
对浏览器中存储的数据(如localStorage和IndexedDB)的访问按来源分开。每个源都有自己的独立存储,一个源中的JavaScript不能从属于另一个源的存储读写。
页面可以使用自己的域或者任何父域设置cookie。无论使用哪种协议(HTTP/HTTPS)或端口,浏览器都将使cookie对给定域(包括任何子域)可用。设置cookie时,可以使用域、路径、安全和仅http标志限制其可用性。当您读取cookie时,您无法看到它是从何处设置的。即使您只使用安全的https连接,您看到的任何cookie都可能是使用不安全连接设置的