同源限制

浏览器安全基石是“同源政策(same-origin policy)”。

1. 概述

1.1 含义

同源政策由网景公司引入浏览器,目前,所有浏览器都实行这个政策。
所谓“同源”,指的是三个相同。

  • 协议相同
  • 域名相同
  • 端口相同

比如说,http://www.baidu.com/dir/1.html这个网址,协议是http://,域名是www.baidu.com,端口是80(默认端口),它的同源情况如下。

  • http://www.baidu.com/dir/2.html:同源。
  • http://www.qq.com/dir/1.html:不同源,域名不同。
  • https://www.baidu.com/dir/1.html:不同源,协议不同。
  • http://www.baidu.com:8081/dir/1.html:不同源,端口不同。

1.2 目的

同源政策的目的,为了保证用户信息的安全,防止恶意的网站数据窃取。

1.3 限制

目前,如果非同源,共有三种行为受到限制。

  1. 无法接触 非同源网页的DOM。
  2. 无法读取非同源网页的Cookie,LocalStorage和IndexedDB。
  3. 无法向非同源地址发送AJAX请求。

通过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()

2. Cookie

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=/

3. iframe和多窗口通信

iframe元素可以在当前网页之中,嵌入其他网页。每个iframe元素形成自己的窗口,即有自己的window对象。iframe窗口之中的脚本,可以获得父窗口和子窗口。但是,只有在同源的情况下,父窗口和子窗口才能通信;如果跨域,就无法拿到对方的 DOM。

如果两个窗口一级域名相同,只是二级域名不同,那么设置document.domain属性,就可以规避同源政策,拿到 DOM。

对于完全不同源的网站,以下方法,可以解决跨域窗口的通信问题。

  1. 片段识别符
  2. 跨文档通信API

3.1 片段标识符

片段标识符指的是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;
}

3.2 window.postMessage()

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,具有三个属性:

  1. event.source:发送消息的窗口。
  2. event.origin:消息发向的网址。
  3. event.data:消息的内容。

4. AJAX

同源政策规定,AJAX 请求只能发给同源的网址,否则就报错。
除了架设服务器代理(浏览器请求同源服务器,再由后者请求外部服务),有三种方法规避这个限制。

  • JSONP
  • WebSocket
  • CORS

由于篇幅有限,AJAX部分暂时点到为止。

5. 参考链接

本篇博文是我自己学习笔记,原文请参考阮一峰JavaScript教程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值