同源策略

浏览器的同源策略 《web之困》p135-p144

Dom的同源策略

除非javascript代码所处两个页面的协议DNS域名(主机名)端口,都完全相同,否则两个独立的javascript运行环境不能访问彼此的dom,其它的任何跨文档Javascript dom访问也会失败。

document.domain

通过修改document.domain来使两个顶级域名相同的网站,跨过同源检查。

因为Dom的同源策略,导致原本属于同一站点的网站不能互相访问,例如sub1.example.comsub2.example.com

1
2
3
# hosts配置
127.0.0.1 sub1.example.com
127.0.0.1 sub2.example.com
1
2
3
4
5
6
7
8
9
10
11
12
<!-- sub1.example.com/index.html -->
<html>
<body>
<iframe src="sub2.example.com/iframe.html"></iframe>
</body>
<script>
const iframe = document.getElementsByTagname('iframe')[0];
console.log(iframe.contentDocument); // null
iframe.contentWindow.String
// VM946:1 Uncaught DOMException: Blocked a frame with origin "http://d1.wocao.com" from accessing a cross-origin frame.
</script>
</html>

为了使这两个子域名不相同的页面可以跨页面访问,我们只需要在连个页面中分别加上<script>document.domain='example.com';</script>

postMessage

通过postMeeage这个Api,来实现父子间信息的传递。这个Api不受same-origin Policy同源策略的限制,只需要获取接收信息方窗口的JavaScript句柄就可以向对应窗口发送信息。下面是一个父子页面互相通信的例子。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!-- sub1.example.com/index.html -->
<html>
<body>
<iframe src="sub2.example.com/iframe.html"></iframe>
<button onclick="clickE()">发送信息到iframe</button>
</body>
<script>
const iframe = document.getElementsByTagName("iframe")[0];

// 对收到信息的事件进行注册
window.addEventListener("message", (msg) => {
// 对发送方进行检查
if (msg.origin === 'http://d2.wocao.com') {
// ...
}
});
function clickE() {
iframe.contentWindow.postMessage("user=tsdy", "http://d2.wocao.com");
}
</script>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!-- sub2.example.com/index.html -->
<html>
<body>
<button onclick="clickE()">发送信息到父页面</button>
</body>
<script>
function clickE() {
parent.postMessage('user=tsdy', 'http://d1.wocao.com');
}
window.addEventListener('message', msg => {
// 对发送方进行检查
if (msg.origin === 'http://d1.wocao.com') {
// ...
}
})
</script>
</html>

XMLHttpRequest的同源策略

通过XMLHttpRequest请求时,不能使用document.domain实现跨域访问。const xhr = new XMLHttpRequest();``xhr.open();目标url地址必须真正与发起的页面同源。

Web Storage的同源策略

在同协议,同dns域名,同端口的情况下共享web storage。在使用iframe时,只要父子页面的顶级域名相同,只需要同时设置document.domain就可以通过跨域dom访问,访问子页面的web storage。或者使用postMessage互相通信。