一.什么是浏览器跨域限制?本质是什么?
所谓浏览器跨域限制,其实是为了数据安全的考虑由Netscape提出来限制浏览器访问跨域数据的策略。
这是一种约定,正式叫法为“浏览器同源策略”,目前已经在大多数浏览器中支持。
本质上,所谓浏览器同源策略,即:不允许浏览器访问跨域的Cookie,ajax请求跨域接口等。
也就是说,凡是访问与自己不在相同域的数据或接口时,浏览器都是不允许的。
最常见的例子:对于前后端完全分离的Web项目,前端页面通过rest接口访问数据时,会出现如下问题:
- 不允许发送POST请求:在发送POST请求之前会发送OPTIONS请求,HTTP响应状态码为403(Forbidden)。
- 允许发送GET请求:HTTP响应状态码为200,但是不能读取服务器返回的数据。
同时,在浏览器(firefox调试)控制台可以看到如下提示:已拦截跨源请求:同源策略禁止读取位于 http://host:port/path 的远程资源。(原因:CORS 头缺少 'Access-Control-Allow-Origin')
。
对URL来说,所谓的“同源”包含3个要素:协议相同,主机名(域名或IP地址,IP地址则看做是根域名)相同,端口相同。
举例来说,对于http://test.chench.org/page.html
这个地址,以下情况被认为是同源与不同源的:
URL | 结果 | 原因 | 说明 |
---|---|---|---|
http://test.chench.org/page2.html | 同源 | 协议相同,主机名相同,端口相同 | |
http://test.chench.org/dir2/page.html | 同源 | 协议相同,主机名相同,端口相同 | 相同域名下的不同目录 |
http://102.12.34.123/page.html | 不同源 | 主机不同 | 域名与域名对应ip也不同源 |
http://test2.chench.org/page.html | 不同源 | 主域名相同,子域名不同 | |
http://chench.org/page.html | 不同源 | 域名不同 | 相同一级域名,不同二级域名 |
http://test.chench.org:81/page.html | 不同源 | 端口不同 | 相同域名,不同端口 |
https://test.chench.org/page.html | 不同源 | 协议不同 | 相同域名,不同协议 |
http://blog.icehoney.me/page.html | 不同源 | 主机不同 | 不同域名 |
二.为什么会存在浏览器跨域限制?
既然目前各主流浏览器都存在跨域限制,那么为什么一定要存在这个限制呢?如果没有跨域限制会出现什么问题?
浏览器同源策略的提出本来就是为了避免数据安全的问题,即:限制来自不同源的“document”或脚本,对当前“document”读取或设置某些属性。
如果没有这个限制,将会出现什么问题?不妨看一下几个情形:
- 可能a.com的一段JavaScript脚本,在b.com未曾加载此脚本时,也可以随意涂改b.com的页面。
- 在浏览器中同时打开某电商网站(域名为b.com),同时在打开另一个网站(a.com),那么在a.com域名下的脚本可以读取b.com下的Cookie,如果Cookie中包含隐私数据,后果不堪设想。
- 因为可以随意读取任意域名下的Cookie数据,很容易发起CSRF攻击。
所以,同源策略是浏览器安全的基础,同源策略一旦出现漏洞被绕过,也将带来非常严重的后果,很多基于同源策略制定的安全方案都将失去效果。
三.对于浏览器来说,哪些资源(操作)会受到同源策略的限制?
对于浏览器来说,除了DOM,Cookie,XMLHttpRequest会受到同源策略的限制外,浏览器加载的一些第三方插件也有各自的同源策略。
最常见的一些插件如Flash,Java Applet,Silverlight,Google Gears等都有自己的控制策略。
另外,存储在浏览器中的数据,如LocalStorage和IndexedDB,以源进行分割。每个源都拥有自己单独的存储空间,一个源中的Javascript脚本不能对属于其它源的数据进行读写操作。
四.浏览器跨域限制会带来什么问题?
随着互联网的发展,对用户体验的要求越来越高,AJAX应用也就越发频繁,AJAX的本质就是XMLHttpRequest。
但XMLHttpRequest受到同源策略的约束,所以不能跨域访问资源,这与我们的期望是相违背的。
五.解决浏览器跨域限制的方法有哪些?如何选择合适的方案?
1. JSONP
在浏览器中,<script>
,<img>
,<iframe>
,<link>
等标签都可以跨域加载资源,而不受同源策略的限制。
这些带"src"属性的标签每次加载时,实际上是由浏览器发起了一次GET请求。
不同于XMLHttpRequest的是,通过src属性加载的资源,浏览器限制了JavaScript的权限,使其不能读写返回的内容。
<script src="..."></script>
标签嵌入跨域脚本。<link rel="stylesheet" href="...">
标签嵌入CSS。由于CSS的松散的语法规则,CSS的跨域需要一个设置正确的Content-Type消息头。不同浏览器有不同的限制。<img>
嵌入图片。支持的图片格式包括PNG,JPEG,GIF,BMP,SVG,...<video>
和<audio>
嵌入多媒体资源。<object>
,<embed>
和<applet>
的插件。@font-face
引入的字体。一些浏览器允许跨域字体(ross-origin fonts),一些需要同源字体(same-origin fonts)。<frame>
和<iframe>
载入的任何资源。站点可以使用X-Frame-Options消息头来阻止这种形式的跨域交互。
JSONP就是利用这个特性,通过javascript标签加载资源的方式请求跨域接口数据,间接绕开了浏览器同源策略的限制。
具体来说,就是在DOM中通过动态创建javascript标签,并给标签设置src属性,在访问请求参数中传递需要回调的函数名;
同时,服务端在响应jsonp请求时,将数据作为请求参数指定的客户端回调函数参数作为返回值,这样对于客户端来说服务器的响应数据其实是回调函数的参数,是javascipt对象,而不是字符串,因此避免了使用JSON.parse的步骤。
2. CORS(Cross-Origin Resource Sharing)
CORS是一个解决浏览器跨域限制的W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。
它允许浏览器向跨域服务器发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
具体来说,根据CORS标准定义,服务端需要在浏览器的跨域请求响应中包含指定消息头,浏览器根据响应消息头知道是否可以访问跨域资源。
3. WebSocket
WebSocket是一种通信协议,使用ws://(非加密)和wss://(加密)作为协议前缀。
该协议不实行同源政策,只要服务器支持,就可以通过它进行跨源通信。
4. 解决方法总结
方案 | 优点 | 缺点 |
---|---|---|
JSONP | 简单实用,老式浏览器全部支持,服务器改造非常小。 | 只支持GET请求,不支持POST等其他类型的HTTP请求,不能解决跨域页面之间的javasript调用问题。 |
CORS | W3C标准,是跨源AJAX请求的根本解决方法,允许任何类型的请求。 | |
WebSocket | 不受浏览器同源策略影响 | 需要服务端支持协议,浏览器支持websocket,并非所有浏览器都支持websocket。 |
【参考】
https://github.com/acgotaku/WebSecurity/blob/master/docs/content/Browser_Security/Same-Origin-Policy.md 同源策略基本介绍
https://developer.mozilla.org/zh-CN/docs/Web/Security/Same-origin_policy 浏览器的同源策略
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS HTTP access control (CORS)
http://www.ruanyifeng.com/blog/2016/04/same-origin-policy.html 浏览器同源政策及其规避方法
https://www.zhihu.com/question/25427931 对于浏览器的同源策略你是怎样理解的呢?
http://www.cnblogs.com/rainman/archive/2011/02/20/1959325.html#m1 JavaScript跨域总结与解决办法
https://www.zhihu.com/question/26379635 为什么浏览器要限制跨域访问?