最初,同源策略的含义是指,网页A设置的cookie,网页B不能打开,除非这两个网页“同源”,如下:
- 协议相同
- 域名相同
- 端口相同
举例来说,http://www.example.com/dir/page.html
的同源情况如下:
http://www.example.com/dir2/other.html
:同源http://example.com/dir/other.html
:不同源(域名不同)http://v2.www.example.com/dir/other.html
:不同源(域名不同)http://www.example.com:81/dir/other.html
:不同源(端口不同)
同源策略的目的是为了保证用户信息的安全,防止恶意的网站窃取数据。
随着互联网的发展,同源策略越来越严格,目前共有三种行为收到限制:
- Cookie、LocalStorage和IndexedDB无法读取;
- DOM无法获得;
- AJAX请求不能发送。
如何规避
Cookie
Cookie是服务器写入浏览器的一小段信息,只有同源的网页才能共享。但是,两个网页一级域名相同,只是二级域名不同,浏览器允许通过设置document.domain
共享cookie
。
举例来说,网页A是http://w1.example.com/a.html
,网页B是http://w2.example.com/b.html
。那么只要设置相同的document.domain
,两个网页就可以共享cookie
。
注意,这种方法只适用于cookie
和iframe
窗口,LocalStorage
和IndexedDB
是不行的,而要使用PostMessage
API。
此外,服务器可以在设置cookie
的时候,指定cookie
所属域名为一级域名,比如.example.com
,这样,二级域名和三级域名不用做任何设置,都可以读取这个cookie
。
iframe
如果两个网页不同源,就无法拿到对方的DOM。典型的例子是iframe
和window.open()
打开的窗口与父窗口无法通信。
如果两个窗口一级域名相同,只是二级域名不同,那么设置document.domain
属性就可以。
对于完全不同源的网站,目前有三种方法:
- 片段识别符(fragment identifier)
- window.name
- 跨文档通信API(cross-document messageing)
片段识别符
片段识别符(fragment identifier)是指URL的#
后面的部分,如果只是改变片段标识符,页面不会重新刷新。
父窗口可以把信息写入子窗口的片段标识符,子窗口监听hashchange
事件得到通知。
1 | // 父 |
window.name
无论是否同源,只要在一个窗口里,前一个网页设置的window.name
,后一个网页就可以读取它。
优点是容量大,可以放置很长的字符串;缺点是必须监听属性变化的事件,影响性能。
postMessage
HTML5提供了跨文档通信API(Cross-document messaging)postMessage
,允许跨窗口通信,不论这两个窗口是否同源。
1 | // 父窗口向子窗口 |
event
对象的三个属性:
event.source
:发送消息的窗口event.origin
:消息发向的网址event.data
:消息内容
LocalStorage
通过window.postMessage
可以读写其他窗口的LocalStorage
。
1 | // 子窗口接收父窗口消息 |
AJAX
AJAX请求只能发给同源网址,有三种方法规避这个限制:
- JSONP
- WebSocket
- CORS