摘要:同源策略及跨域访问同源策略同源策略约束了两个域之间资源的加载方式,是一个很重要的安全机制用来隔离那些有潜在安全隐患的文档。
同源策略及跨域访问 同源策略
同源策略(Same-origin policy)约束了两个域之间资源的加载方式,是一个很重要的安全机制用来隔离那些有潜在安全隐患的文档。
何为源(orgin)一个源由一个URL的协议(protocol)、主机(host)和端口(port)进行定义。如果两个页面拥有相同的协议、主机和端口一致的话,我们就可以称它们为同源。下面的表格比较了不同的URL跟http://store.company.com/dir/page.html这个URL的同源情况:
URL | 是否同源 | 理由 |
---|---|---|
http://store.company.com/dir2... | 是 | |
http://store.company.com/dir/... | 是 | |
https://store.company.com/sec... | 否 | 协议不同 |
http://store.company.com:81/d... | 否 | 端口不同 |
http://news.company.com/dir/o... | 否 | 主机不同 |
同源策略控制了两个源之间的交互,例如你使用XMLHttpRequest发起一个请求,或者使用元素加载一张图片,就会产生两个源之间的交互。而当两个源不相同时,有些交互会被允许,而有些则不被允许。而不允许的情况,就是我们常说的跨域访问问题。那什么情况下不同源的交互会被允许,什么情况下又不被允许呢?大致可以分为如下的情况:
链接、跳转和表单提交这些在跨域的情况下都是被允许的。例如调用支付宝接口进行支付就是典型的跨域表单提交的场景,这种跨域的调用是被允许的。但是这个很容易被利用来进行CSRF攻击,所以我们的表单提交需要做好这方面的防护。
跨域的资源内嵌是被允许的。下面是一些资源内容的例子:
使用加载Javascript。只有同源的脚本在语法错误时会显示错误信息。
使用加载CSS。跨源的CSS文件要求使用正确的Content-Type 响应头。
使用加载图片。
使用和加载媒体文件。
使用 、和加载插件。
使用 @font-face加载字体。有些浏览器允许加载跨域的字体,有些则不允许。
使用 和加载任何东西。
跨域文档间使用Javascript脚本进行交互,API的访问有限制。例如使用ifame嵌入的页面或者使用window.open打开的页面,如果跟父页面不同源,则想通过Javascript去操作父页面的DOM,是不允许的(反过来亦然)。
举个例子,假设有这么一个页面http://www.example.com/index.html:
.....
然后在http://sub.example.com/iframe.html页面对父页面的背景色进行修改:
......
由于两个页面不同源,所以子页面对父页面的操作被禁止,例如在Firefox上你会看到以下的报错:
Error: Permission denied to access property "document"
不同源之间的XMLHttpRequest调用(也就是我们常说ajax调用)是不被允许的,这个也是我们最常遇到的跨域访问场景。例如我们在http://example.com/index.html页面进行如下的ajax调用:
var xhr = new XMLHttpRequest(); var url = "http://otherexample.com/api/get-data"; xhr.open("GET", url, true); xhr.onreadystatechange = handler; xhr.send();
在Firefox下会报如下错误:
已拦截跨源请求:同源策略禁止读取位于 http://otherexample.com/api/get-data 的远程资源。(原因:CORS 头缺少 "Access-Control-Allow-Origin")。跨域访问的解决方案
一个页面的源是可以修改的,修改的方法很简单,就是通过Javascript脚本设置document.domain的值。举个例子,我们在页面http://store.company.com/dir/other.html执行下面的代码:
document.domain = "company.com";
那么这个页面的域将会由store.company.com变成company.com,后面在判断是否同源的时候,主机将会使用company.com这个值,而不是store.company.com。
那是不是修改域后就能跟同域的页面进行交互呢。答案是否定的。例如,如果你在页面中通过iframe嵌入http://company.com/dir/page.html这个页面,然后通过javascript去跟这个页面交互,你会发现浏览器会报错,就跟我们之前那个例子一样。按照上面的源的定义,这时候两个页面应该是同源的,为什么呢?因为修改document.domain会导致端口号被设为null。所以另外一个页面也需要把document.domain修改为相同的值,这样两个页面的主机和端口就一致了,可以进行互相的访问了。
既然源可以修改,那么是不是就解决了我们的跨域问题呢?明显没这么简单。首先,这种方法是有很大限制条件的,document.domain这个值只能修改为这个页面的当前域或者当前域的超级域。所以,这个方法只能解决同一超级域下的页面跨域问题。其次,它的使用场景也很有限,因为它需要页面执行Javascript脚本,所以也就是说一般只能应用于页面跟页面的交互,例如访问ifame页面或者window.open打开的页面等等。所以如果你想用来解决ajax之类的跨域调用,这个方法就无能为力了。
使用代理也是解决跨域访问的一个方法。上面修改document.domain的方法只能用来访问子域名的页面,无法访问不同域的页面,而使用代理则没有这个问题。
例如我们有一个页面http://example.com/,需要访问http://otherexample.com/这个页面,我们不直接对这个页面进行访问,而是通过请求另外一个同源的页面,这个页面在后端通过代理服务器把请求转发到http://otherexample.com/,获取数据并返回给客户端。
另外,这个方法同样可以用于解决ajax的跨域访问问题。
JSONP也被经常用来解决ajax的跨域调用问题。JSONP请求并不是通过XMLHttpRequest发起,而是使用进行调用。前面说过,内嵌资源一般不受同源政策影响,所以可以加载其他源的资源。
举个例子,假设http://www.example.com/页面,想异步调用http://www.otherexample.com/ajax.json这个接口,这个接口会返回如下的数据:
{ "id": "123", "name": "Captain Jack Sparrow" }
如果我们通过XMLHttpRequest发起调用,就会因为同源政策而失败。所以我们通过进行调用,并通过参数传递我们的回调函数名:
然后接口获取到callback函数名后,把原来返回的数据作为函数的参数,最终返回如下的Javascript:
myFunction({"id": "123", "name": "Captain Jack Sparrow"});
然后myFunction就会执行,达到了调用的目的。
这个方法在大多数情况下都很有用,但是它也有它的局限。一是它需要后端的配合,因为后端的接口需要根据约定的参数获取回调函数名,然后跟返回数据进行拼接,最后进行响应。二是它只能进行异步的调用,因为它的原理是通过动态生成加载JS的方法,而这个过程是异步的,所以如果你想进行同步的调用,那么这个方法就无能为力了。
Web Messaging(又称cross-document messaging)是HTML5的一个接口,允许两个不同源的文档之间进行通信。
它主要用到了接口里的postMessage方法,这个方法可以把纯文本消息从一个域发送到另外一个域。消息可以发送以下的对象:
发送方文档里frame和iframe。
发送方通过Javascript打开的页面。
发送方的父页面。
打开发送方页面的页面。
消息event包含了以下的属性:
data:收到的消息。
origin:发送方的源,包括协议、主机名和端口。
source:发送方的window对象。
举个例子,假设example.net下的文档A跟文档里用iframe加载的example.com下的文档B进行通信,我们向文档B发送消息Hello B,Javascript代码大致如下:
var o = document.getElementsByTagName("iframe")[0]; o.contentWindow.postMessage("Hello B", "http://example.com/");
我们先获取到文档B的contentWindow对象,然后把需要发送到消息以及文档B的源传给postMessage。文档B则通过监听message事件,捕获到事件,并作相应的处理:
function receiver(event) { if (event.origin == "http://example.net") { if (event.data == "Hello B") { event.source.postMessage("Hello A, how are you?", event.origin); } else { alert(event.data); } } } window.addEventListener("message", receiver, false);
需要注意的是,postMessage是个非阻塞的调用,也就是说是异步的。
Web Messaging主要用于跨域文档间的通讯,所以它不能用来解决所有跨域调用的问题,例如ajax调用。而且IE浏览器对它的支持也很有限。
CORS(Cross-Origin Resource Sharing)是W3C提出的一个用于服务器端控制数据跨域传输的一个机制。 它的原理是通过一些新增加的HTTP头让服务端能定义哪些源的请求可以被允许。
简单举个例子,假设我们在页面http://example.com/发起一个跨域的XMLHttpRequest请求:
var xhr = new XMLHttpRequest(); var url = "http://otherexample.com/api/get-data/"; xhr.open("GET", url, true); xhr.onreadystatechange = handler; xhr.send();
正常情况这个请求是不允许的。但是如果我们在服务端返回以下响应头:
Access-Control-Allow-Origin: *
这个Access-Control-Allow-Origin头表示服务端允许哪些源的请求,*表示允许所有的源,所以上面的请求就被允许了。当然正常情况下我们不会这样做,我们需要把Access-Control-Allow-Origin设置为真正想允许的源。在请求头会有一个叫Origin的头,它的值就是请求方的源(例如上面的请求会有Origin: http://example.com这个请求头),服务端应该根据这个头去返回相应的Access-Control-Allow-Origin头。
当然CORS的实际使用会比上面的例子复杂得多,具体可以参考MDN的这篇文章和W3C的规范。
CORS可以说是解决XMLHttpRequest跨域调用的一个比较好的方法,但IE浏览器对它的支持同样很有限,直到IE11才完全支持,所以在移动端更能发挥它的作用。
参考https://developer.mozilla.org...
https://developer.mozilla.org...
https://www.sitepoint.com/wor...
https://en.wikipedia.org/wiki...
http://caniuse.com/#search=po...
http://caniuse.com/#search=cors
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/11219.html
摘要:三哪些会受到同源策略限制对于浏览器来说,除了会受到同源策略的限制外,浏览器加载的一些第三方插件也有各自的同源策略。九的现代浏览器允许脚本直连一个地址而不管同源策略。 一、Origin(源) 源由下面三个部分组成: 域名 端口 协议 两个 URL ,只有这三个都相同的情况下,才可以称为同源。 下来就以 http://www.example.com/page.html 这个链接来比较说...
摘要:扯了这么多,自然不是为了吹水,而是要为了引出前端开发的一个重要的知识点同源策略什么是同源策略出于保护用户信息安全的目的,现在的浏览器都会实施同源策略这个政策,所谓同源策略指的是不同源的客户端脚本在没有明确授权情况下,不允许读写对方的资源。 导语你家的小孩带了他的朋友来你们的家里玩,你家的小孩如果要在自家屋里拿玩具玩、拿东西吃你自然是不会阻止,但是如果你家小孩的朋友人品不行,乱拿东西吃、...
摘要:扯了这么多,自然不是为了吹水,而是要为了引出前端开发的一个重要的知识点同源策略什么是同源策略出于保护用户信息安全的目的,现在的浏览器都会实施同源策略这个政策,所谓同源策略指的是不同源的客户端脚本在没有明确授权情况下,不允许读写对方的资源。 导语你家的小孩带了他的朋友来你们的家里玩,你家的小孩如果要在自家屋里拿玩具玩、拿东西吃你自然是不会阻止,但是如果你家小孩的朋友人品不行,乱拿东西吃、...
摘要:同源策略是什么同源策略是浏览器的一个安全功能,不同源的数据禁止访问。或许你可以说验证,在浏览器没有同源策略的情况下这些都可以绕过去。总结同源策略是蛮好的,防御了大部分的攻击。 前端最基础的就是 HTML+CSS+Javascript。掌握了这三门技术就算入门,但也仅仅是入门,现在前端开发的定义已经远远不止这些。前端小课堂(HTML/CSS/JS),本着提升技术水平,打牢基础知识的中心思...
摘要:上节我们讲了同源策略,这节我们讲讲如何跨域。当这些从的脚本执行出错,因为违背了同源策略为了保证用户信息不被泄露,错误信息不会显示出来,取而代之只会返回一个。 前端最基础的就是 HTML+CSS+Javascript。掌握了这三门技术就算入门,但也仅仅是入门,现在前端开发的定义已经远远不止这些。前端小课堂(HTML/CSS/JS),本着提升技术水平,打牢基础知识的中心思想,我们开课啦(每...
阅读 1681·2021-11-12 10:36
阅读 1597·2021-11-12 10:36
阅读 3403·2021-11-02 14:46
阅读 3759·2019-08-30 15:56
阅读 3459·2019-08-30 15:55
阅读 1428·2019-08-30 15:44
阅读 1028·2019-08-30 14:00
阅读 2715·2019-08-29 18:41