同源策略及跨域

来源:互联网 发布:贴吧发帖软件 编辑:程序博客网 时间:2024/05/16 05:45

同源策略

同源策略(Same Origin Policy)是一种约定。浏览器同源策略是浏览器安全的基础。

浏览器的同源策略,限制了来自于不同源的“document”或脚本,对当前“document”读取或设置某些属性。

影响“源”的因素有:host(域名或IP地址,如果是IP地址可以看做一个根域名)、子域名、端口、协议。

URL由协议、域名、端口和路径组成,如果两个URL的协议、域名和端口相同,则表示他们同源

浏览器中<script>、<img>、<iframe>、<link>等标签都可以跨域加载资源,而不受同源策略的限制。Src加载资源时其实是由浏览器发起了一次GET请求。不同于XMLHttpRequest的是,通过src属性加载的资源,浏览器限制了JavaScript的权限,使其不能读、写返回内容。

XMLHttpRequest收到同源策略的约束,不能跨域访问资源。

如果XMLHttpRequest能够跨域访问资源,则可能会导致一些敏感数据泄露,比如CSRF的token,从而导致发生安全问题。

XMLHttpReqest需要通过目标域返回的HTTP头来授权是否允许跨域访问,因为HTTP头对于JavaScript来说一般是无法控制的,这个跨域访问方案的安全基础就是信任“JavaScript无法控制该HTTP头”。

跨域

通过设置Access-Control-Allow-Origin来实现跨域访问。如果设置了这些头部并允许某些域名跨域访问,则浏览器就会跳过同源策略的限制返回对应的内容。此外,如果你不是通过浏览器去获取资源,比如你通过一个python脚本去调用接口或者获取js文件,也不在这个限制之内。

通过ajax调用其他域的接口会有跨域问题。比如下面的例子,我在http://www.foo.com/index.html中通过ajax调用请求http://www.bar.com/js/test.js页面,此时是会报错的。

Ajax跨域

通过ajax调用其他域的接口会有跨域问题。比如下面的例子,我在http://www.foo.com/index.html中通过ajax调用请求http://www.bar.com/js/test.js页面,此时是会报错的。

这是因为我们的WEB服务器没有设置ACCESS-CONTROL-ALLOW-ORIGIN头部,默认情况下是禁止跨域引用资源的。当然这里有一点要注意,其实这个跨域请求是发送成功了的,服务器也有返回test.js内容,只是浏览器禁止Javascript去取response的数据而已。如果要设置ACCESS-CONTROL-ALLOW-ORIGIN头部,nginx可以使用下面的代码:

add_header 'Access-Control-Allow-Origin' 'http://www.foo.com';add_header 'Access-Control-Allow-Credentials' 'true';add_header 'Access-Control-Allow-Methods' 'GET,POST';

另外,我们看到直接通过Javascript去取iframe中的元素也是会报错的。

因为我们的主域名相同,因此可以在index.html和test.html中设置document.domain=’foo.com’来访问iframe中的元素。注意,是两个域名下面的文件都要设置,即便是同样的主域名。当然这是特例,如果是两个完全不同的域名,是没有办法的,你不能把www.foo.com的domain设置成www.163.com。

JSONP跨域访问

JSONP也是开发中常见到的内容,在jquery中就有封装,通过ajax请求多带上一个jsonp的参数即可。JSONP也能够实现跨域访问资源,但是它的实现原理其实跟ajax没有多少关系,它是通过动态插入<script>标签来实现跨域资源访问的,因为根据前面内容我们已经知道,嵌入跨域资源浏览器是允许的。

简单说明JSONP的原理:

两个文件,第一个是http://www.foo.com/jsonp.html,通过动态创建script标签加载了http://www.bar.com/js/outer.js文件,然后outer.js文件返回的内容正好是一个函数调用,如此,实现了数据传递和回调过程。当然,实际的jsonp接口中,会让你传一个函数名过去,然后返回的数据中回调函数名就是你传的函数名,回调函数的参数则是封装的json格式。jQuery中的jsonp实现原理基本就是这样。

# jsonp.html<script type="text/javascript">    function callback(data) {        alert(data.message);    }    function addScriptTag(src){    var script = document.createElement('script');        script.src = src;        document.body.appendChild(script);    }    window.onload = function(){        addScriptTag("http://www.foo.com/js/outer.js");    }</script># outer.jscallback({message:"success"});