起源 - 面试中or日常开发中会遇到的跨域问题
- 为什么
<img> <script> <link> <from action="xxx">可以跨域? - 为什么
<canvans>标签再绘制图片的时候会存在跨域? - 为什么
javascript发起xhr请求会存在跨域?
本质:同源策略是一个重要的安全策略,它用于限制一个origin的文档或者它加载的脚本如何能与另一个源的资源进行交互。它能帮助阻隔恶意文档,减少可能被攻击的媒介。
同源的定义
如果两个 URL 的 protocol、port (如果有指定的话)和 host 都相同的话,则这两个 URL 是同源。这个方案也被称为“协议/主机/端口元组”,或者直接是 “元组”。(“元组” 是指一组项目构成的整体,双重/三重/四重/五重/等的通用形式)。
- 下表给出了与 URL store.company.com/dir/page.ht… 的源进行对比的示例:
| URL | 结果 | 原因 |
|---|---|---|
| store.company.com/dir2/other.… | 同源 | 只有路径不同 |
| store.company.com/dir/inner/a… | 同源 | 只有路径不同 |
| store.company.com/secure.html | 失败 | 协议不同 |
| store.company.com:81/dir/etc.htm… | 失败 | 端口不同 ( http:// 默认端口是80) |
| news.company.com/dir/other.h… | 失败 | 主机不同 |
源的继承
在页面中通过 about:blank 或 javascript: URL 执行的脚本会继承打开该 URL 的文档的源,因为这些类型的 URLs 没有包含源服务器的相关信息。
例如,about:blank 通常作为父脚本写入内容的新的空白弹出窗口的 URL(例如,通过 Window.open() )。 如果此弹出窗口也包含 JavaScript,则该脚本将从创建它的脚本那里继承对应的源
IE中特性
Internet Explorer 的同源策略有两个主要的差异点:
-
授信范围(Trust Zones):两个相互之间高度互信的域名,如公司域名(corporate domains),则不受同源策略限制。
-
端口:IE 未将端口号纳入到同源策略的检查中,因此 company.com:81/index.html 和 company.com/index.html 属于同源并且不受任何限制。
这些差异点是不规范的,其它浏览器也未做出支持,但会助于开发基于window RT IE的应用程序.
跨源网络访问
同源策略控制不同源之间的交互,例如在使用XMLHttpRequest 或 <img> 标签时则会受到同源策略的约束。这些交互通常分为三类:
-
跨域写操作(Cross-origin writes)一般是被允许的。例如链接(links),重定向以及表单提交。特定少数的HTTP请求需要添加 preflight。
-
跨域资源嵌入(Cross-origin embedding)一般是被允许(后面会举例说明)。
-
跨域读操作(Cross-origin reads)一般是不被允许的,但常可以通过内嵌资源来巧妙的进行读取访问。例如,你可以读取嵌入图片的高度和宽度,调用内嵌脚本的方法,或 availability of an embedded resource.
下面就可以解释文章开头的问题
<script src="..."></script>标签嵌入跨域脚本。语法错误信息只能被同源脚本中捕捉到。<link rel="stylesheet" href="...">标签嵌入CSS。由于CSS的松散的语法规则,CSS的跨域需要一个设置正确的 HTTP 头部 Content-Type 。不同浏览器有不同的限制: IE, Firefox, Chrome, Safari (跳至CVE-2010-0051)部分 和 Opera。- 通过
<img>展示的图片。支持的图片格式包括PNG,JPEG,GIF,BMP,SVG,... - 通过
<video>和<audio>播放的多媒体资源。 - 通过
<object>、 <embed>和<applet>嵌入的插件。 - 通过
@font-face引入的字体。一些浏览器允许跨域字体(cross-origin fonts),一些需要同源字体(same-origin fonts)。 - 通过
<iframe>载入的任何资源。站点可以使用 X-Frame-Options 消息头来阻止这种形式的跨域交互。
如何允许跨域访问
跨域主要有JSONP、CORS、postMessage、WebSocket
如何阻止跨域访问
- 阻止跨域写操作,只要检测请求中的一个不可推测的标记(CSRF token)即可,这个标记被称为 Cross-Site Request Forgery (CSRF) 标记。你必须使用这个标记来阻止页面的跨站读操作。
- 阻止资源的跨站读取,需要保证该资源是不可嵌入的。阻止嵌入行为是必须的,因为嵌入资源通常向其暴露信息。
- 阻止跨站嵌入,需要确保你的资源不能通过以上列出的可嵌入资源格式使用。浏览器可能不会遵守 Content-Type 头部定义的类型。例如,如果您在HTML文档中指定
跨源脚本API访问
JavaScript 的 API 中,如 iframe.contentWindow、 window.parent、window.open 和 window.opener 允许文档间直接相互引用。当两个文档的源不同时,这些引用方式将对 Window 和 Location对象的访问添加限制。
为了能让不同源中文档进行交流,可以使用window.postMessage。
规范: HTML Living Standard § Cross-origin objects 。
允许以下对 Window 属性的跨源访问:
| 方法 |
|---|
window.blur |
window.close |
window.focus |
window.postMessage |
| 属性 | |
|---|---|
window.closed | 只读. |
window.frames | 只读. |
window.length | 只读. |
window.location | 读/写. |
window.opener | 只读. |
window.parent | 只读. |
window.self | 只读. |
window.top | 只读. |
window.window | 只读. |
某些浏览器允许访问除上述外更多的属性。
允许以下对 Location 属性的跨源访问: |方法| |----| |
location.replace|
| 属性 | |
|---|---|
URLUtils.href | 只写 |
某些浏览器允许访问除上述外更多的属性。
跨源数据存储访问
访问存储在浏览器中的数据,如 localStorage 和 IndexedDB,是以源进行分割。每个源都拥有自己单独的存储空间,一个源中的 JavaScript 脚本不能对属于其它源的数据进行读写操作。
Cookies 使用不同的源定义方式。一个页面可以为本域和其父域设置 cookie,只要是父域不是公共后缀(public suffix)即可。Firefox 和 Chrome 使用 Public Suffix List 检测一个域是否是公共后缀(public suffix)。Internet Explorer 使用其内部的方法来检测域是否是公共后缀。不管使用哪个协议(HTTP/HTTPS)或端口号,浏览器都允许给定的域以及其任何子域名(sub-domains) 访问 cookie。当你设置 cookie 时,你可以使用 Domain、Path、Secure、和 HttpOnly 标记来限定其可访问性。当你读取 cookie 时,你无法知道它是在哪里被设置的。 即使您只使用安全的 https 连接,您看到的任何 cookie 都有可能是使用不安全的连接进行设置的。