关于跨域那些事~~

浏览器跨域是一个前端很常见的问题。

造成跨域的两种策略浏览器的同源策略会导致跨域,这里同源策略又分为以下两种DOM同源策略:

1.禁止对不同源页面DOM进行操作。这里主要场景是iframe跨域的情况,不同域名的iframe是限制互相访问的。
//例如
let iframeSon = document.getElementById("myIframe").contentWindow.document.getElementById("son");
        console.log(iframeSon)   

如果是iframe和本页面为不同的源页面的情况下


image.png

我们就会出现上图的报错

2.XmlHttpRequest同源策略:禁止使用XHR对象向不同源的服务器地址发起HTTP请求。只要协议、域名、端口有任何一个不同,都被当作是不同的域,之间的请求就是跨域操作。

AJAX同源策略主要用来防止CSRF攻击。如果没有AJAX同源策略,相当危险,我们发起的每一次HTTP请求都会带上请求地址对应的cookie,那么可以做如下攻击:

  1. 用户登录了自己的银行页面 http://mybank.comhttp://mybank.com向用户的cookie中添加用户标识。
  2. 用户浏览了恶意页面 http://evil.com。执行了页面中的恶意AJAX请求代码。
  3. http://evil.comhttp://mybank.com发起AJAX HTTP请求,请求会默认把http://mybank.com对应cookie也同时发送过去。
  4. 银行页面从发送的cookie中提取用户标识,验证用户无误,response中返回请求数据。此时数据就泄露了。
  5. 而且由于Ajax在后台执行,用户无法感知这一过程。

DOM同源策略也一样,如果iframe之间可以跨域访问,可以这样攻击:

  1. 做一个假网站,里面用iframe嵌套一个银行网站 http://mybank.com
  2. 把iframe宽高啥的调整到页面全部,这样用户进来除了域名,别的部分和银行的网站没有任何差别。
  3. 这时如果用户输入账号密码,我们的主网站可以跨域访问到http://mybank.com的dom节点,就可以拿到用户的输入了,那么就完成了一次攻击。
    (如果账号密码你感觉不会让你损失钱,你可以试着输入一下信用卡卡号+安全码,然后你就能感觉到花钱的快乐)

所以说有了跨域跨域限制之后,我们才能更安全的上网了。

CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。

它允许浏览器向跨源服务器,发出[XMLHttpRequest]请求,从而克服了AJAX只能[同源]使用的限制。

下面是一个例子,浏览器发现这次跨源AJAX请求是简单请求,就自动在头信息之中,添加一个Origin字段。

GET /cors HTTP/1.1
Origin: http://api.bob.com
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
对于客户端,我们还是正常使用xhr对象发送ajax请求。

唯一需要注意的是,我们需要设置我们的xhr属性withCredentials为true,不然的话,cookie是带不过去的,
设置:

 xhr.withCredentials = true; 
对于服务器端,需要在 response header中设置如下两个字段:
Access-Control-Allow-Origin: [http://www.yourhost.com](https://link.zhihu.com/?target=http%3A//www.yourhost.com)
Access-Control-Allow-Credentials:true

这样,我们就可以跨域请求接口了。

jsonp实现跨域

基本原理就是通过动态创建script标签,然后利用src属性进行跨域。

demo.js
// 定义一个fun函数
function fun(fata) {
    console.log(data);
};
// 创建一个脚本,并且告诉后端回调函数名叫fun
var body = document.getElementsByTagName('body')[0];
var script = document.gerElement('script');
script.type = 'text/javasctipt';
script.src = 'demo.js?callback=fun';
body.appendChild(script);

这样就能获取到数据的同时直接执行demo.js中的fun函数

postMessage实现跨域

ES5新增的 postMessage() 方法允许来自不同源的脚本采用异步方式进行有限的通信,可以实现跨文本档、多窗口、跨域消息传递.
语法: postMessage(data,origin)
data: 要传递的数据,html5规范中提到该参数可以是JavaScript的任意基本类型或可复制的对象,然而并不是所有浏览器都做到了这点儿,部分浏览器只能处理字符串参数,所以我们在传递参数的时候建议使用JSON.stringify()方法对对象参数序列化,在低版本IE中引用json2.js可以实现类似效果.
origin:字符串参数,指明目标窗口的源,协议+主机+端口号[+URL],URL会被忽略,所以可以不写,这个参数是为了安全考虑,postMessage()方法只会将message传递给指定窗口,当然如果愿意也可以建参数设置为”*”,这样可以传递给任意窗口,如果要指定和当前窗口同源的话设置为”/“。
父页面发送消息:

window.frames[0].postMessage('message', origin)

iframe接受消息:

window.addEventListener('message',function(e){
    if(e.source!=window.parent) return;//若消息源不是父页面则退出
      //TODO ...
});

其中 e 对象有三个重要的属性

1.data, 表示父页面传递过来的message
2.source, 表示发送消息的窗口对象
3.origin, 表示发送消息窗口的源(协议+主机+端口号)

document.domain来进行跨域

通过修改document的domain属性,我们可以在域和子域或者不同的子域之间通信(即它们必须在同一个一级域名下). 同域策略认为域和子域隶属于不同的域,比如a.com和 script.a.com是不同的域,这时,我们无法在a.com下的页面中调用script.a.com中定义的JavaScript方法。但是当我们把它们document的domain属性都修改为a.com,浏览器就会认为它们处于同一个域下,那么我们就可以互相获取对方数据或者操作对方DOM了。
比如, 我们在 www.a.com/a.html 下, 现在想获取 www.script.a.com/b.html, 即主域名相同, 二级域名不同. 那么可以这么做:

document.domain = 'a.com';
var iframe = document.createElement('iframe');
iframe.src = 'http://www.script.a.com/b.html';
iframe.style.display = 'none';
document.body.appendChild(iframe);
iframe.addEventListener('load',function(){
    //TODO 载入完成时做的事情
    //var _document = iframe.contentWindow.document;
     //...
},false);

注意:
2个页面都要设置, 哪怕 a.html 页已处于 a.com 域名下, 也必须显式设置.
document.domain只能设置为一级域名,比如这里a页不能设置为www.a.com (二级域名).
利用domain属性跨域具有以下局限性:
两个页面要在同一个一级域名下, 且必须同协议, 同端口, 即子域互跨;
只适用于iframe(几乎没luan用 ̄へ ̄)

Internet Explorer同源策略绕过

Internet Explorer8以及前面的版本很容易通过document.domain实现同源策略绕过, 通过重写文档对象, 域属性这个问题可以十分轻松的被利用.

var document;
document = {};
document.domain = 'http://www.a.com';
console.log(document.domain);

如果你在最新的浏览器中运行这段代码, 可能在JavaScript控制台会显示一个同源策略绕过错误(真正没luan用(艹皿艹))

底下的文章中还有几个不常用的方法,都几乎是在特定的情况下才能生效,就不一一解释了。

那么我们插件中又是怎么解决跨域的呢?
在插件中的background是不受域的限制的,因此可以轻松发送ajax请求给其他网站。
background的权限非常高,几乎可以调用所有的Chrome扩展API(除了devtools),而且它可以无限制跨域,也就是可以跨域访问任何网站而无需要求对方设置CORS。

经过测试,其实不止是background,所有的直接通过chrome-extension://id/xx.html这种方式打开的网页都可以无限制跨域。

然后说说上周发现插件的一个坑

最近要做一个页面可以内嵌许多其他的外部网页,于是使用了iframe
然后使用iframe的时候少许网页会出现这种情况


image.png

那么这个X-Frame-Options又是个啥呢?

X-Frame-Options是什么?

X-Frame-Options是一个HTTP标头(header),用来告诉浏览器这个网页是否可以放在iFrame内。例如:

X-Frame-Options: DENY X-Frame-Options: SAMEORIGIN X-Frame-Options: ALLOW-FROM http://caibaojian.com/

第一个例子告诉浏览器不要(DENY)把这个网页放在iFrame内,通常的目的就是要帮助用户对抗点击劫持。

第二个例子告诉浏览器只有当架设iFrame的网站与发出X-Frame-Options的网站相同,才能显示发出X-Frame-Options网页的内容。

第三个例子告诉浏览器这个网页只能放在http://caibaojian.com//网页架设的iFrame内。

不指定X-Frame-Options的网页等同表示它可以放在任何iFrame内。

X-Frame-Options可以保障你的网页不会被放在恶意网站设定的iFrame内,令用户成为点击劫持的受害人。

简单的来说,这东西就是用来阻止自己的网页被嵌套在iframe中然后被网站盗取资料的
但是如果你装了chrome插件的话在background中进行一个这样的设置,就可以绕过网站的设置

chrome.webRequest
使用 chrome.webRequest API 监控与分析流量,还可以实时地拦截、阻止或修改请求。


image.png
onBeforeRequest(可以为同步)

当请求即将发出时产生。这一事件在 TCP 连接建立前发送,可以用来取消或重定向请求。

onBeforeSendHeaders(可以为同步)

当请求即将发出并且初始标头已经准备好时产生。这一事件是为了使扩展程序能够添加、修改和删除请求标头(*)。onBeforeSendHeaders 事件将传递给所有订阅者,所以不同的订阅者都可以尝试修改请求。有关具体如何处理的细节,请参见实现细节部分。这一事件可以用来取消请求。

onSendHeaders

当所有扩展程序已经修改完请求标头并且展现最终版本时产生。这一事件在标头发送至网络前触发,仅用于提供信息,并且以异步方式处理,不允许修改或取消请求。

onHeadersReceived(可以为同步)

每当接收到 HTTP(S) 响应标头时产生。由于重定向以及认证请求,对于每次请求这一事件可以多次产生。这一事件是为了使扩展程序能够添加、修改和删除响应标头,例如传入的 Set-Cookie 标头。缓存指示是在该事件触发前处理的,所以修改 Cache-Control 之类的标头不会影响浏览器的缓存。它还允许您重定向请求。

onAuthRequired(可以为同步)

当请求需要用户认证时产生。这一事件可以同步处理,提供认证凭据。注意,扩展程序提供的凭据可能无效,注意不要重复提供无效凭据,陷入无限循环。

onBeforeRedirect

当重定向即将执行时产生,重定向可以由 HTTP 响应代码或扩展程序触发。这一事件仅用于提供信息,并以异步方式处理,不允许修改或取消请求。

onResponseStarted

当接收到响应正文的第一个字节时产生。对于 HTTP 请求,这意味着状态行和响应标头已经可用。这一事件仅用于提供信息,并以异步方式处理,不允许修改或取消请求。

onCompleted

当请求成功处理后产生。

onErrorOccurred

当请求不能成功处理时产生。
网络请求 API 保证对于每一个请求,onCompleted 或 onErrorOccurred 是最终产生的事件,除了如下例外:如果请求重定向至 data:// URL,######onBeforeRedirect 将是最后报告的事件。

这里我们主要使用的是onHeadersReceived

chrome.webRequest.onHeadersReceived.addListener(
  (details)=> {
    for (var i = 0; i < details.responseHeaders.length; ++i) {
      if (details.responseHeaders[i].name.toLowerCase() == 'x-frame-options') {
        details.responseHeaders.splice(i, 1);
        return {
          responseHeaders: details.responseHeaders
        };
      }
    }
  }, {
    urls: ["*://zhihu.com/*"]
  }, ["blocking", "responseHeaders"]);

这里我们主要的就是用onSendHeaders,大家可以看到代码中,每当接收到 HTTP(S) 响应标头时,将会获取到其中的responseHeaders,然后将其中的‘x-frame-options’这个设置给砍掉。这样浏览器的最终结果就成功绕过了iframe的设置,强行的将网页变成内嵌的iframe。
至于浏览器的安全问题。。。。。
。。
你都装了这么流氓的插件了,我们网站能咋办,自己背锅。

文章资料来源
http://www.ruanyifeng.com/blog/2016/04/cors.html
http://louiszhai.github.io/2016/01/11/cross-domain/
https://crxdoc-zh.appspot.com/extensions/webRequest#implementation

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容

  • 原文地址:原文地址 什么是跨域? 跨域是指一个域下的文档或脚本试图去请求另一个域下的资源,这里跨域是广义的。 广义...
    C_Y大渔阅读 1,255评论 1 13
  • 什么是跨域? 2.) 资源嵌入:、、、等dom标签,还有样式中background:url()、@font-fac...
    电影里的梦i阅读 2,363评论 0 5
  • 什么是跨域 跨域,是指浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对JavaScript实...
    HeroXin阅读 830评论 0 4
  • 什么是跨域 跨域,是指浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对JavaScript实...
    Yaoxue9阅读 1,286评论 0 6
  • 12月9日,2016中国国际智慧教育展览会在国家会议中心举行。展会以“智慧+教育跨界新融合”为主题,通过教育信息化...
    因酷时代阅读 160评论 0 0