浏览器安全基石是“同源政策(same-origin policy)”。
同源政策由网景公司引入浏览器,目前,所有浏览器都实行这个政策。
所谓“同源”,指的是三个相同。
比如说,http://www.baidu.com/dir/1.html这个网址,协议是http://,域名是www.baidu.com,端口是80(默认端口),它的同源情况如下。
同源政策的目的,为了保证用户信息的安全,防止恶意的网站数据窃取。
目前,如果非同源,共有三种行为受到限制。
通过JavaScript可以拿到其他窗口的window
对象。如果是非同源网页,目前允许一个窗口可以接触其他网页的window
对象的九个属性和方法。
window.closed
:布尔值,窗口是否关闭(只读)。window.frames
:返回一个类似数组的对象,成员为页面内所有框架窗口,包括frame
元素和iframe
元素(只读)。window.length
:返回当前网页包含的框架总数。如果当前网页不包含frame
元素和iframe
元素,那么window.length
就返回0(只读)。window.location
:指向Location
对象,用于获取当前窗口的 URL 信息(读写)。window.opener
:打开当前窗口的父窗口,如果没有返回null(只读)。window.parent
:指向父窗口。如果当前窗口没有父窗口,window.parent
指向自身(只读)。window.self
:指向窗口本身(只读)。window.top
:指向最顶层窗口,主要用于在框架窗口(frame
)里面获取顶层窗口(只读)。window.window
:指向窗口本身(只读)。window.blur()
:将焦点从窗口移除。window.close()
:用于关闭当前窗口,一般只用来关闭window.open
方法新建的窗口。window.focus()
:激活窗口,使其获得焦点,出现在其他窗口的前面。window.postMessage()
Cookie 是服务器写入浏览器的一小段信息,只有同源的网页才能共享。如果两个网页一级域名相同,只是次级域名不同,浏览器允许通过设置document.domain
共享 Cookie。
比如,A网页网址为http://www.baidu.com/a.html
,B网页网址为http://www.baidu.com/b.html
。只需要设置相同的document.domain
,两个网页就能共享Cookie。浏览器是根据document.domain
属性检查是否同源。
// A网页
document.domain = "www.baidu.com";
// A网页设置一个cookie
document.cookie = "testCookie=a";
// B网页
document.domain = "www.baidu.com";
// B网页可以读取A网页的Cookie
var cookieOfB = document.cookie;
还可以通过服务器设置Cookie,指定Cookie的所属域名为一级域名。这样的话,子域名不用做任何设置,就能读取Cookie。
Set-Cookie: key=value; domain=.baidu.com; path=/
iframe
元素可以在当前网页之中,嵌入其他网页。每个iframe
元素形成自己的窗口,即有自己的window
对象。iframe
窗口之中的脚本,可以获得父窗口和子窗口。但是,只有在同源的情况下,父窗口和子窗口才能通信;如果跨域,就无法拿到对方的 DOM。
如果两个窗口一级域名相同,只是二级域名不同,那么设置document.domain
属性,就可以规避同源政策,拿到 DOM。
对于完全不同源的网站,以下方法,可以解决跨域窗口的通信问题。
片段标识符指的是URL的#
后面的部分,如果只是改变片段标识符,页面不会刷新。
父窗口通过片段标识符,写入信息。
var data = "name=jidi&age=23"
var src = URLOfSun + "#" + data;
document.getElementById("MySunFrame").src = src;
子窗口通过监听hashchange
事件得到通知。
window.onhashchange = function{
// 获取片段标识符
var message = window.location.hash;
}
HTML5 引入了一个全新的API:跨文档通信 API。这个 API 为window
对象新增了一个window.postMessage
方法,允许跨窗口通信,不论这两个窗口是否同源。
// 父窗口打开一个子窗口
var sun = window.open("www.baidu.com", "百度");
// 父窗口向子窗口发送消息
sun.postMessage("你好,我是你爸爸!", "www.baidu.com");
// 子窗口向父窗口发送消息
window.opener.postMessage("你好,我是你儿子!",window.opener.location.href)
// 父窗口和子窗口可以通过message事件,监听对方消息
window.addEventListener("message", function(event){
//获取消息
var message = event.data;
}, false);
message
事件的参数是事件对象event
,具有三个属性:
event.source
:发送消息的窗口。event.origin
:消息发向的网址。event.data
:消息的内容。同源政策规定,AJAX 请求只能发给同源的网址,否则就报错。
除了架设服务器代理(浏览器请求同源服务器,再由后者请求外部服务),有三种方法规避这个限制。
由于篇幅有限,AJAX部分暂时点到为止。
本篇博文是我自己学习笔记,原文请参考阮一峰JavaScript教程。