同源策略

所谓的同源策略,指的是浏览器对不同源的脚本或者文本访问方式进行的限制。
所谓同源,就是指两个页面具有相同的协议,主机(也常说域名),端口,三个要素缺一不可。
同源政策的目的,是为了保证用户信息的安全,防止恶意的网站窃取数据。
如果一个用户在登陆一个网站之后又去访问其他网站,如果其他网站可以读取上一个网站的cookie,就会导致个人信息泄露。

限制范围

随着互联网的发展,"同源政策"越来越严格。目前,如果非同源,共有三种行为受到限制:
1、cookie、localstorage、indexDB(IndexedDB 是一种低级API,用于客户端存储大量结构化数据(包括, 文件/ blobs)。该API使用索引来实现对该数据的高性能搜索。)无法读取
2、DOM无法获得。
3、AJAX请求不能发送。

规避措施

1、cookie

Cookie是服务器写入浏览器的一小段信息,只有同源的网页才能共享,但是两个网页只有一级域名相同,只是二级域名不同,浏览器允许通过设置document.domain共享Cookie。
举例来说,A,http://w1.example.com/a.html B,http://w2.example.com/b.html,那么只要设置相同的document.domain,两个网页就可以共享Cookie。
document.domain='example.com'
A通过脚本设置一个Cookie:document.cookie='text=hello'
B网页就可以读到这个Cookie。var allCookie=document.cookie;
  • 这种方法只适用于Cookie和iframe窗口,LocalStorage和IndexDB无法通过这种方法,规避同源政策。需要使用PostMessage API。另外,服务器也可以在设置Cookie的所属域名为一级域名,比如:.example.com。

    Set-Cookie:key=value;domain=.example.com; path=/

    这样的话,二级域名和三级域名不用做任何设置都可以读取这个Cookie。

2、iframe

如果两个网页不同源,就无法拿到对方的DOM。典型的例子是iframe窗口和window.open方法打开的窗口,他们与父窗口无法通信。
比如,父窗口运行下面的命令,如果iframe不同源就会导致错误,document.getElementById('myIframe').contentWindow.document,上面的命令中,父窗口想获取子窗口的DOM,因为跨源导致报错。反之亦然。
如果两个完全不同源的网站,目前有三种方法,可以解决跨域窗口的通信问题。
1、片段识别符(fragment identifier)
2、window.name
3、跨文档通信API(Cross-document messaging)
  • 片段识别符

    指的是URL的#号后面的部分,比如 http://example.com/x.html#fragment的#fragment。如果只是改变片段标识符,页面不会重新刷新。父窗口可以把信息,写入子窗口的片段标识符。

    var src=originURL+'#'+data;

    document.getElementById('myIFrame')

    子窗口通过监听hashchange事件得到通知。

    window.onhashchange=checkMessage;

    function checkMessage(){

    var message=window.location.hash;

    }

    同样的,子窗口也可以改变父窗口的片段标识符。

    parent.location.href=target+'#'+data;

  • window.name

    浏览器窗口有window.name属性,这个属性的最大特点是,无论是否同源,只要在同一个窗口,前一个网页设置了这个属性,后一个网页就可以读取他。

    父窗口先打开一个子窗口,载入一个不同源的网页,该网页将信息写入window.name属性。

    window.name = data;

    接着,子窗口跳回一个与主窗口同域的网址。

    location = 'http://parent.url.com/xxx.html';

    然后,主窗口就可以读取子窗口的window.name了。

    var data = document.getElementById('myFrame').contentWindow.name;

    这种方法的优点是,window.name容量很大,可以放置非常长的字符串;缺点是必须监听子窗口window.name属性的变化,影响网页性能。

  • window.postMessage

    上面两种方法都属于破解,HTML5为了解决这个问题,引入了一个全新的API:跨文档通信 API(Cross-document messaging)。

    这个API为window对象新增了一个window.postMessage方法,允许跨窗口通信,不论这两个窗口是否同源。

    举例来说,父窗口http://aaa.com向子窗口http://bbb.com发消息,调用postMessage方法就可以了。

    var popup = window.open('http://bbb.com', 'title');

    popup.postMessage('Hello World!', 'http://bbb.com');

    postMessage方法的第一个参数是具体的信息内容,第二个参数是接收消息的窗口的源(origin),即"协议 + 域名 + 端口"。也可以设为*,表示不限制域名,向所有窗口发送。

    子窗口向父窗口发送消息的写法类似。

    window.opener.postMessage('Nice to see you', 'http://aaa.com');

    父窗口和子窗口都可以通过message事件,监听对方的消息。

    window.addEventListener('message', function(e) {

    console.log(e.data);

    },false);

    message事件的事件对象event,提供以下三个属性。

    event.source:发送消息的窗口

    event.origin: 消息发向的网址

    event.data: 消息内容

    下面的例子是,子窗口通过event.source属性引用父窗口,然后发送消息。

    window.addEventListener('message', receiveMessage);
function receiveMessage(event) {
event.source.postMessage('Nice to see you!', '*');
}
event.origin属性可以过滤不是发给本窗口的消息。
    window.addEventListener('message', receiveMessage);
function receiveMessage(event) {
if (event.origin !== 'http://aaa.com') return;
if (event.data === 'Hello World') {
event.source.postMessage('Hello', event.origin);
} else {
console.log(event.data);
}
}

3、LocalStorage

通过window.postMessage,读写其他窗口的 LocalStorage 也成为了可能。
下面是一个例子,主窗口写入iframe子窗口的localStorage。
window.onmessage = function(e) {
if (e.origin !== 'http://bbb.com') {
return;
}
var payload = JSON.parse(e.data);
localStorage.setItem(payload.key, JSON.stringify(payload.data));
};
上面代码中,子窗口将父窗口发来的消息,写入自己的LocalStorage。
父窗口发送消息的代码如下。
var win = document.getElementsByTagName('iframe')[0].contentWindow;
var obj = { name: 'Jack' };
win.postMessage(JSON.stringify({key: 'storage', data: obj}), 'http://bbb.com');
加强版的子窗口接收消息的代码如下。
      if (e.origin !== 'http://bbb.com') return;
var payload = JSON.parse(e.data);
switch (payload.method) {
case 'set':
localStorage.setItem(payload.key, JSON.stringify(payload.data));
break;
case 'get':
var parent = window.parent;
var data = localStorage.getItem(payload.key);
parent.postMessage(data, 'http://aaa.com');
break;
case 'remove':
localStorage.removeItem(payload.key);
break;
}
};
加强版的父窗口发送消息代码如下。
    var win = document.getElementsByTagName('iframe')[0].contentWindow;
var obj = { name: 'Jack' };
// 存入对象
win.postMessage(JSON.stringify({key: 'storage', method: 'set', data: obj}), 'http://bbb.com');
// 读取对象
win.postMessage(JSON.stringify({key: 'storage', method: "get"}), "*");
window.onmessage = function(e) {
if (e.origin != 'http://aaa.com') return;
// "Jack"
console.log(JSON.parse(e.data).name);
};

JavaScript中的跨域详解(一)的更多相关文章

  1. JavaScript中的跨域详解(二)

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

  2. javascript中=、==、===区别详解

    javascript中=.==.===区别详解今天在项目开发过中发现在一个小问题.在判断n==""结果当n=0时 n==""结果也返回了true.虽然是个小问题 ...

  3. JavaScript中return的用法详解

    JavaScript中return的用法详解 最近,跟身边学前端的朋友了解,有很多人对函数中的this的用法和指向问题比较模糊,这里写一篇博客跟大家一起探讨一下this的用法和指向性问题. 1定义 t ...

  4. javascript 中合并排序算法 详解

    javascript 中合并排序算法 详解 我会通过程序的执行过程来给大家合并排序是如何排序的...  合并排序代码如下: <script type="text/javascript& ...

  5. javascript中的this作用域详解

    javascript中的this作用域详解 Javascript中this的指向一直是困扰我很久的问题,在使用中出错的机率也非常大.在面向对象语言中,它代表了当前对象的一个引用,而在js中却经常让我觉 ...

  6. JavaScript中this的用法详解

    JavaScript中this的用法详解 最近,跟身边学前端的朋友了解,有很多人对函数中的this的用法和指向问题比较模糊,这里写一篇博客跟大家一起探讨一下this的用法和指向性问题. 1定义 thi ...

  7. JavaScript中的跨域

    跨域是什么 跨域就是指从一个域名的网页去请求另一个域名的资源,因为JavaScript同源策略的限制,资源无法获取.比如从www.baidu.com 页面去请求 www.google.com 的资源, ...

  8. 跨域详解之jsonp,底层的实现原理

    分享一下跨域,不仅是因为现在的工作中遇到的越来越多,而且在面试中也经常被问到. 那么什么是跨域呢,我们来看官方给出的解释:浏览器不能执行其他网站的脚本.它是由浏览器的同源策略造成的(所谓同源是指,域名 ...

  9. JavaScript中数组Array方法详解

    ECMAScript 3在Array.prototype中定义了一些很有用的操作数组的函数,这意味着这些函数作为任何数组的方法都是可用的. 1.Array.join()方法 Array.join()方 ...

随机推荐

  1. 基于sklearn进行文本向量化

    sklearn中,计数向量化用CountVectorizer,tfidf向量化用TfidfVectorizer: import pickle from sklearn.feature_extracti ...

  2. 2018秋C语言程序设计(初级)作业- 第3次作业

    7-1 找出最小值 #include<stdio.h> int main() { int min,i,n,count; scanf("%d",&n); for( ...

  3. HDU - 4339: Query(bitset暴力找下一个为1的)

    题意:给定A,B长度相同的字符串,Q次操作,修改操作位单个字符修改,查询操作为询问从某点开始有多少连续相同的字符. 思路:我们把不相同的设为1,相同的设为0,那么询问就是找下一个为1的为位置,可以用线 ...

  4. Windows7 下python3和python2同时 安装python3和python2

    1.下载python3和python2 进入python官网,链接https://www.python.org/ 选择Downloads--->Windows,点击进入就可以看到寻找想要的pyt ...

  5. scrapy 伪装代理和fake_userAgent的使用

    伪装浏览器代理 在爬取网页是有些服务器对请求过滤的不是很高可以不用ip来伪装请求直接将自己的浏览器信息给伪装也是可以的. 第一中方法: 1.在setting.py文件中加入以下内容,这是一些浏览器的头 ...

  6. Spring Cloud feign 服务超时处理

    Spring Cloud中,Feign和Ribbon在整合了Hystrix后,可能会出现首次调用失败的问题 造成该问题的原因 Hystrix默认的超时时间是1秒,如果超过这个时间尚未响应,将会进入fa ...

  7. c++重在运算符

    运算符函数的定义与其他函数的定义类似,惟一的区别是运算符函数的函数名是由关键字operator和其后要重载的运算符符号构成的.运算符函数定义的一般格式如下: <返回类型说明符> opera ...

  8. bzoj 2406 矩阵——有源汇上下界可行流

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2406 二分答案.把 b 的 n 个行作为一排, m 个列作为一排,每行和每列之间连上下界为 ...

  9. mac系统PHP 7.1.12安装xhprof并使用[View Full Callgraph]小记

    前几天从php7.0.x 升级到了php7.2.0版本, 结果装xhprof没有找到能支持对应版本的xhprof 于是又安装了一个php7.1.2的版本(brew install h) 接着安装xhp ...

  10. [转]nginx虚拟目录(alias与root的区别)

    今天配置awstats,awstats创建出的文件目录在/home/awstats下,在nginx中加入配置后狂报404,发现还是忽略了root和alias的区别,特将修改配置记录如下: 1.失败:s ...