同源策略--笔记
1. 概述
- 含义
- 所谓“同源”指的是”三个相同“。
- 协议相同
- 域名相同
- 端口相同
- 举例来说,http://www.example.com/dir/page.html 这个网址,协议是 http://,域名是 www.example.com,端口是80(默认端口可以省略),它的同源情况如下。
- 所谓“同源”指的是”三个相同“。
- 目的
- 同源政策的目的,是为了保证用户信息的安全,防止恶意的网站窃取数据
- 限制范围
- 随着互联网的发展,同源政策越来越严格。目前,如果非同源,共有三种行为受到限制。
- 无法读取非同源网页的 Cookie、LocalStorage 和 IndexedDB。
- 无法接触非同源网页的 DOM。
- 无法向非同源地址发送 AJAX 请求(可以发送,但浏览器会拒绝接受响应)。
- 虽然这些限制是必要的,但是有时很不方便,合理的用途也受到影响。下面介绍如何规避上面的限制。
- 随着互联网的发展,同源政策越来越严格。目前,如果非同源,共有三种行为受到限制。
2. Cookie
Cookie 是服务器写入浏览器的一小段信息,只有同源的网页才能共享。如果两个网页一级域名相同,只是次级域名不同,浏览器允许通过设置document.domain共享 Cookie。
举例来说,A 网页的网址是 http://w1.example.com/a.html, B 网页的网址是 http://w2.example.com/b.html,那么只要设置相同的document.domain,两个网页就可以共享 Cookie。因为浏览器通过document.domain属性来检查是否同源。
1
2// 两个网页都需要设置
document.domain = 'example.com';注意,A 和 B 两个网页都需要设置document.domain属性,才能达到同源的目的。因为设置document.domain的同时,会把端口重置为null,因此如果只设置一个网页的document.domain,会导致两个网址的端口不同,还是达不到同源的目的。
- 注意,这种方法只适用于 Cookie 和 iframe 窗口,LocalStorage 和 IndexedDB 无法通过这种方法,规避同源政策,而要使用下文介绍 PostMessage API
3. iframe
- iframe元素可以在当前网页之中,嵌入其他网页。每个iframe元素形成自己的窗口,即有自己的window对象。iframe窗口之中的脚本,可以获得父窗口和子窗口。但是,只有在同源的情况下,父窗口和子窗口才能通信;如果跨域,就无法拿到对方的 DOM。
- 如果两个窗口一级域名相同,只是二级域名不同,那么设置上一节介绍的document.domain属性,就可以规避同源政策,拿到 DOM。对于完全不同源的网站,目前有两种方法,可以解决跨域窗口的通信问题。
- 片段识别符
- window.postMessage()
- window对象新增了一个window.postMessage方法,允许跨窗口通信,不论这两个窗口是否同源
- postMessage方法的第一个参数是具体的信息内容,第二个参数是接收消息的窗口的源(origin),即“协议 + 域名 + 端口”。也可以设为*,表示不限制域名,向所有窗口发送。
- 父窗口和子窗口都可以通过message事件,监听对方的消息。
- message事件的参数是事件对象event,提供以下三个属性。
- event.source:发送消息的窗口
- event.origin: 消息发向的网址
- event.data: 消息内容
- LocalStorage
- 通过window.postMessage,读写其他窗口的 LocalStorage 也成为了可能
4. AJAX
- 同源政策规定,AJAX 请求只能发给同源的网址,否则就报错。除了架设服务器代理(浏览器请求同源服务器,再由后者请求外部服务),有三种方法规避这个限制。
- JSONP
- WebSocket
- CORS
JSONP
- 它的基本思想是,网页通过添加一个 script 元素,向服务器请求 JSON 数据,这种做法不受同源政策限制;服务器收到请求后,将数据放在一个指定名字的回调函数里传回来。
1
2
3
4
5
6
7
8
9
10
11
12
13
14function addScriptTag(src) {
var script = document.createElement('script');
script.setAttribute("type","text/javascript");
script.src = src;
document.body.appendChild(script);
}
window.onload = function () {
addScriptTag('http://example.com/ip?callback=foo');
}
function foo(data) {
console.log('Your public IP address is: ' + data.ip);
};
WebSocket
- WebSocket 是一种通信协议,使用ws://(非加密)和wss://(加密)作为协议前缀。该协议不实行同源政策,只要服务器支持,就可以通过它进行跨源通信
- CORS