【技术分享】同源策略和跨域的简单理解

语言: CN / TW / HK

点击关注“八戒技术团队”,阅读更多技术干货

同源策略的概念要追溯到1995年的网景浏览器。所有的现代浏览器都在一定程度上实现了同源策略,它 作为一个重要的安全基石, 虽然不是一个明确规范,但是经常为某些web技术或者某些机制(例如XMLHttpRequest)扩展定义大致兼容的安全边界。

同源策略下,web浏览器允许第一个页面的脚本访问第二个页面里的数据(只有在两个页面有相同的源时, 源是由URI,主机名,端口号组合而成的 )。 这个策略可以阻止一个页面上的恶意脚本通过页面的DOM对象获得访问另一个页面上敏感信息的权限。

对于普遍依赖于cookie维护授权用户session的现代浏览器来说,这种机制有特殊意义,客户端必须在不同站点提供的内容之间维持一个严格限制,以防丢失数据机密或者完整性。

源决定规则

对于绝对的URIs,源就是{协议,主机,端口}定义的。只有这些值完全一样才认为两个资源是同源的。

为了举例,下面的表格给出了与URL"http://www.lcy.com/dir/page.html"的对比。

对比URL 结果 结果

http://www.lcy.com/dir/page2.html

同源

相同的协议,主机,端口

http://www.lcy.com/dir2/other.html

同源

相同的协议,主机,端口

http://username:[email protected]/dir2/other.html

同源

相同的协议,主机,端口

http://www.lcy.com:81/dir/other.html

不同源

相同的协议,主机,端口不同

https://www.lcy.com/dir/other.html

不同源

协议不同

http://en.lcy.com/dir/other.html

不同源

不同主机

http://lcy.com/dir/other.html

不同源

不同主机(需要精确匹配)

http://v2.www.lcy.com/dir/other.html

不同源

不同主机(需要精确匹配)

http://www.lcy.com:80/dir/other.html

看情况

端口明确,依赖浏览器实

IE中的特例:IE在计算源的时候没有包括端口。

我们了解了同源策略的概念后,现实生活中某些场景,则存在不同源之间的访问,数据传递。 同源策略主要表现在网络、 DOM和web数据这三个层面。

CORS 跨域

不同于JSONP,CORS是以Ajax方式进行跨域请求,需要服务端与客户端的同时支持。目前CORS在绝大部分现代浏览器中都是支持的,IE不能低于IE10。 浏览器一旦发现 AJAX 请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。 因此,实现 CORS 通信的关键是服务器,只要服务器实现了 CORS 接口,就可以跨源通信。

浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。

只要同时满足以下两大条件,就属于 简单请求

1.请求方法是以下三种方法之一:

  • HEAD

  • GET

  • POST

1.HTTP的头信息不超出以下几种字段:

  • Accept

  • Accept-Language

  • Content-Language

  • Last-Event-ID

  • Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

凡是不同时满足上面两个条件,就属于 非简单请求

浏览器对这两种请求的处理,是不一样的。

对于非简单请求,浏览器在发送真正的请求之前,会先发送一个Preflight请求给服务器,称为”预检“请求,这种请求使用OPTIONS方法,且预检请求时 浏览器将不会发送cookies,即使你的XHR设置了withCredentials

接下来简单介绍几种常见的跨域时用到的响应头以及需要注意的点,避免踩坑:

1.Access-Control-Allow-Methods: 必要字段 ,表示服务器支持的所有跨域请求方法,只要浏览器使用的请求方法包含在内即可通过。注意,返回的是所有支持的方法,而不单是浏览器请求的那个方法。这是为了避免多次”预检”请求。

2.Access-Control-Allow-Origin: 必要字段 ,该站点可以被哪些网站进行跨域资源共享

没有这个头部或者有这个头部但源信息不匹配,浏览器就会驳回请求。正常情况下,浏览器会处理请求。

3.Access-Control-Expose-Headers: 必要字段 ,表明服务器支持的所有头信息字段,也是为了避免多次预检请求

4.Access-Control-Allow-Headers: 如果浏览器请求包括Access-Control-Request-Headers字段,则Access-Control-Allow-Headers字段是必需的。它也是一个逗号分隔的字符串,表明服务器支持的所有头信息字段,不限于浏览器在”预检”中请求的字段。

5.Access-Control-Allow-Credentials: 跨域Ajax请求时是否带Cookie的设置;表示是否允许发送cookies。默认情况下,Cookies不包括在CORS请求中;设为true表示cookies可以包含在请求中一起发给服务器,如果不需要发送cookies给服务器,需删除字段。

需要注意的是:除了设置Access-Control-Allow-Credential:true外,在ajax请求中也必须打开withCredentials。

JSONP 跨域

CORS与JSONP的使用目的相同,但是比JSONP更强大。

JSONP只支持GET请求,CORS支持所有类型的HTTP请求。JSONP的优势在于支持老式浏览器,以及可以向不支持CORS的网站请求数据。

DOM加载跨域资源

以下三个标签是允许跨域加载资源的:

<img src=”>

<link href=‘’>

<script src=‘’>

document.domain 跨域

对于主域名相同,而子域名不同的情况,可以使用 document.domain 来跨域。这种方式非常适用于 iframe 跨域的情况。

具体做法,在子域名的页面和主域名的页面下都显示设置document.main 为主域名的域名。

如在http://www.lcy.com/a.html 中设置document.domain:

在http://lcy.com/b.html页面也必须设置document.domain, 即使当前页面的域名本身就是lcy.com,但也必须显式的设置document.domain.

这样,子页面就可以通过js访问到主页面的各种属性和对象了。

location.hash 跨域

location.hash 方式跨域,是子框架修改父框架 src 的 hash 值,通过这个属性进行传递数据,且更改 hash 值,页面不会刷新。但是传递的数据的字节数是有限的。

页面 http://www.lcy.com/a.html 的代码:

页面 http://lcy.com/b.html 的代码:

postMessage 跨域

window.postMessage(message,targetOrigin) 方法是 HTML5 新引进的特性,可以使用它来向其它的 window 对象发送消息,无论这个 window 对象是属于同源或不同源。这个应该就是以后解决 dom 跨域通用方法了。

调用 postMessage 方法的 window 对象是指要接收消息的那一个 window 对象,该方法的第一个参数 message 为要发送的消息,类型只能为字符串;第二个参数 targetOrigin 用来限定接收消息的那个 window 对象所在的域,如果不想限定域,可以使用通配符 *。

需要接收消息的 window 对象,可是通过监听自身的 message 事件来获取传过来的消息,消息内容储存在该事件对象的 data 属性中。

页面 http://www.lcy.com/a.html 的代码:

页面 http://lcy.com/b.html 的代码:

可能你还想阅读

希望以上内容能对有需要的人有所帮助

欢迎大家留言写下自己希望了解的技术方向

欢迎大家一起探讨交流

请点击下方名片关注我们

诚邀各位IT大佬加入我们“西南名猿交流群”

一个交流技术、招聘的场地

全国程序猿皆可扫码上车噢~