關(guān)于跨域那些事~~

瀏覽器跨域是一個前端很常見的問題擅这。

造成跨域的兩種策略瀏覽器的同源策略會導(dǎo)致跨域,這里同源策略又分為以下兩種DOM同源策略:

1.禁止對不同源頁面DOM進行操作采章。這里主要場景是iframe跨域的情況运嗜,不同域名的iframe是限制互相訪問的。
//例如
let iframeSon = document.getElementById("myIframe").contentWindow.document.getElementById("son");
        console.log(iframeSon)   

如果是iframe和本頁面為不同的源頁面的情況下


image.png

我們就會出現(xiàn)上圖的報錯

2.XmlHttpRequest同源策略:禁止使用XHR對象向不同源的服務(wù)器地址發(fā)起HTTP請求悯舟。只要協(xié)議担租、域名、端口有任何一個不同抵怎,都被當(dāng)作是不同的域奋救,之間的請求就是跨域操作。

AJAX同源策略主要用來防止CSRF攻擊反惕。如果沒有AJAX同源策略尝艘,相當(dāng)危險,我們發(fā)起的每一次HTTP請求都會帶上請求地址對應(yīng)的cookie姿染,那么可以做如下攻擊:

  1. 用戶登錄了自己的銀行頁面 http://mybank.com背亥,http://mybank.com向用戶的cookie中添加用戶標(biāo)識。
  2. 用戶瀏覽了惡意頁面 http://evil.com悬赏。執(zhí)行了頁面中的惡意AJAX請求代碼狡汉。
  3. http://evil.comhttp://mybank.com發(fā)起AJAX HTTP請求,請求會默認把http://mybank.com對應(yīng)cookie也同時發(fā)送過去舷嗡。
  4. 銀行頁面從發(fā)送的cookie中提取用戶標(biāo)識轴猎,驗證用戶無誤嵌莉,response中返回請求數(shù)據(jù)进萄。此時數(shù)據(jù)就泄露了。
  5. 而且由于Ajax在后臺執(zhí)行锐峭,用戶無法感知這一過程中鼠。

DOM同源策略也一樣,如果iframe之間可以跨域訪問沿癞,可以這樣攻擊:

  1. 做一個假網(wǎng)站援雇,里面用iframe嵌套一個銀行網(wǎng)站 http://mybank.com
  2. 把iframe寬高啥的調(diào)整到頁面全部椎扬,這樣用戶進來除了域名惫搏,別的部分和銀行的網(wǎng)站沒有任何差別具温。
  3. 這時如果用戶輸入賬號密碼,我們的主網(wǎng)站可以跨域訪問到http://mybank.com的dom節(jié)點筐赔,就可以拿到用戶的輸入了铣猩,那么就完成了一次攻擊。
    (如果賬號密碼你感覺不會讓你損失錢茴丰,你可以試著輸入一下信用卡卡號+安全碼达皿,然后你就能感覺到花錢的快樂)

所以說有了跨域跨域限制之后,我們才能更安全的上網(wǎng)了贿肩。

CORS是一個W3C標(biāo)準峦椰,全稱是"跨域資源共享"(Cross-origin resource sharing)。

它允許瀏覽器向跨源服務(wù)器汰规,發(fā)出[XMLHttpRequest]請求汤功,從而克服了AJAX只能[同源]使用的限制。

下面是一個例子溜哮,瀏覽器發(fā)現(xiàn)這次跨源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對象發(fā)送ajax請求。

唯一需要注意的是在抛,我們需要設(shè)置我們的xhr屬性withCredentials為true钟病,不然的話,cookie是帶不過去的刚梭,
設(shè)置:

 xhr.withCredentials = true; 
對于服務(wù)器端肠阱,需要在 response header中設(shè)置如下兩個字段:
Access-Control-Allow-Origin: [http://www.yourhost.com](https://link.zhihu.com/?target=http%3A//www.yourhost.com)
Access-Control-Allow-Credentials:true

這樣,我們就可以跨域請求接口了朴读。

jsonp實現(xiàn)跨域

基本原理就是通過動態(tài)創(chuàng)建script標(biāo)簽,然后利用src屬性進行跨域屹徘。

demo.js
// 定義一個fun函數(shù)
function fun(fata) {
    console.log(data);
};
// 創(chuàng)建一個腳本,并且告訴后端回調(diào)函數(shù)名叫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);

這樣就能獲取到數(shù)據(jù)的同時直接執(zhí)行demo.js中的fun函數(shù)

postMessage實現(xiàn)跨域

ES5新增的 postMessage() 方法允許來自不同源的腳本采用異步方式進行有限的通信衅金,可以實現(xiàn)跨文本檔噪伊、多窗口、跨域消息傳遞.
語法: postMessage(data,origin)
data: 要傳遞的數(shù)據(jù)氮唯,html5規(guī)范中提到該參數(shù)可以是JavaScript的任意基本類型或可復(fù)制的對象鉴吹,然而并不是所有瀏覽器都做到了這點兒,部分瀏覽器只能處理字符串參數(shù)惩琉,所以我們在傳遞參數(shù)的時候建議使用JSON.stringify()方法對對象參數(shù)序列化豆励,在低版本IE中引用json2.js可以實現(xiàn)類似效果.
origin:字符串參數(shù),指明目標(biāo)窗口的源瞒渠,協(xié)議+主機+端口號[+URL]良蒸,URL會被忽略技扼,所以可以不寫,這個參數(shù)是為了安全考慮嫩痰,postMessage()方法只會將message傳遞給指定窗口淮摔,當(dāng)然如果愿意也可以建參數(shù)設(shè)置為”*”,這樣可以傳遞給任意窗口始赎,如果要指定和當(dāng)前窗口同源的話設(shè)置為”/“和橙。
父頁面發(fā)送消息:

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

iframe接受消息:

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

其中 e 對象有三個重要的屬性

1.data, 表示父頁面?zhèn)鬟f過來的message
2.source, 表示發(fā)送消息的窗口對象
3.origin, 表示發(fā)送消息窗口的源(協(xié)議+主機+端口號)

document.domain來進行跨域

通過修改document的domain屬性,我們可以在域和子域或者不同的子域之間通信(即它們必須在同一個一級域名下). 同域策略認為域和子域隸屬于不同的域造垛,比如a.com和 script.a.com是不同的域魔招,這時,我們無法在a.com下的頁面中調(diào)用script.a.com中定義的JavaScript方法五辽。但是當(dāng)我們把它們document的domain屬性都修改為a.com办斑,瀏覽器就會認為它們處于同一個域下,那么我們就可以互相獲取對方數(shù)據(jù)或者操作對方DOM了杆逗。
比如, 我們在 www.a.com/a.html 下, 現(xiàn)在想獲取 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個頁面都要設(shè)置, 哪怕 a.html 頁已處于 a.com 域名下, 也必須顯式設(shè)置.
document.domain只能設(shè)置為一級域名乡翅,比如這里a頁不能設(shè)置為www.a.com (二級域名).
利用domain屬性跨域具有以下局限性:
兩個頁面要在同一個一級域名下, 且必須同協(xié)議, 同端口, 即子域互跨;
只適用于iframe(幾乎沒luan用 ̄へ ̄)

Internet Explorer同源策略繞過

Internet Explorer8以及前面的版本很容易通過document.domain實現(xiàn)同源策略繞過, 通過重寫文檔對象, 域?qū)傩赃@個問題可以十分輕松的被利用.

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

如果你在最新的瀏覽器中運行這段代碼, 可能在JavaScript控制臺會顯示一個同源策略繞過錯誤(真正沒luan用(艸皿艸))

底下的文章中還有幾個不常用的方法,都幾乎是在特定的情況下才能生效罪郊,就不一一解釋了蠕蚜。

那么我們插件中又是怎么解決跨域的呢?
在插件中的background是不受域的限制的悔橄,因此可以輕松發(fā)送ajax請求給其他網(wǎng)站靶累。
background的權(quán)限非常高,幾乎可以調(diào)用所有的Chrome擴展API(除了devtools)癣疟,而且它可以無限制跨域挣柬,也就是可以跨域訪問任何網(wǎng)站而無需要求對方設(shè)置CORS。

經(jīng)過測試睛挚,其實不止是background邪蛔,所有的直接通過chrome-extension://id/xx.html這種方式打開的網(wǎng)頁都可以無限制跨域。

然后說說上周發(fā)現(xiàn)插件的一個坑

最近要做一個頁面可以內(nèi)嵌許多其他的外部網(wǎng)頁扎狱,于是使用了iframe
然后使用iframe的時候少許網(wǎng)頁會出現(xiàn)這種情況


image.png

那么這個X-Frame-Options又是個啥呢侧到?

X-Frame-Options是什么?

X-Frame-Options是一個HTTP標(biāo)頭(header)委乌,用來告訴瀏覽器這個網(wǎng)頁是否可以放在iFrame內(nèi)床牧。例如:

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

第一個例子告訴瀏覽器不要(DENY)把這個網(wǎng)頁放在iFrame內(nèi),通常的目的就是要幫助用戶對抗點擊劫持遭贸。

第二個例子告訴瀏覽器只有當(dāng)架設(shè)iFrame的網(wǎng)站與發(fā)出X-Frame-Options的網(wǎng)站相同,才能顯示發(fā)出X-Frame-Options網(wǎng)頁的內(nèi)容心软。

第三個例子告訴瀏覽器這個網(wǎng)頁只能放在http://caibaojian.com//網(wǎng)頁架設(shè)的iFrame內(nèi)壕吹。

不指定X-Frame-Options的網(wǎng)頁等同表示它可以放在任何iFrame內(nèi)著蛙。

X-Frame-Options可以保障你的網(wǎng)頁不會被放在惡意網(wǎng)站設(shè)定的iFrame內(nèi),令用戶成為點擊劫持的受害人耳贬。

簡單的來說踏堡,這東西就是用來阻止自己的網(wǎng)頁被嵌套在iframe中然后被網(wǎng)站盜取資料的
但是如果你裝了chrome插件的話在background中進行一個這樣的設(shè)置,就可以繞過網(wǎng)站的設(shè)置

chrome.webRequest
使用 chrome.webRequest API 監(jiān)控與分析流量咒劲,還可以實時地攔截顷蟆、阻止或修改請求。


image.png
onBeforeRequest(可以為同步)

當(dāng)請求即將發(fā)出時產(chǎn)生腐魂。這一事件在 TCP 連接建立前發(fā)送帐偎,可以用來取消或重定向請求。

onBeforeSendHeaders(可以為同步)

當(dāng)請求即將發(fā)出并且初始標(biāo)頭已經(jīng)準備好時產(chǎn)生蛔屹。這一事件是為了使擴展程序能夠添加削樊、修改和刪除請求標(biāo)頭(*)。onBeforeSendHeaders 事件將傳遞給所有訂閱者兔毒,所以不同的訂閱者都可以嘗試修改請求漫贞。有關(guān)具體如何處理的細節(jié),請參見實現(xiàn)細節(jié)部分育叁。這一事件可以用來取消請求迅脐。

onSendHeaders

當(dāng)所有擴展程序已經(jīng)修改完請求標(biāo)頭并且展現(xiàn)最終版本時產(chǎn)生。這一事件在標(biāo)頭發(fā)送至網(wǎng)絡(luò)前觸發(fā)豪嗽,僅用于提供信息仪际,并且以異步方式處理,不允許修改或取消請求昵骤。

onHeadersReceived(可以為同步)

每當(dāng)接收到 HTTP(S) 響應(yīng)標(biāo)頭時產(chǎn)生树碱。由于重定向以及認證請求,對于每次請求這一事件可以多次產(chǎn)生变秦。這一事件是為了使擴展程序能夠添加成榜、修改和刪除響應(yīng)標(biāo)頭,例如傳入的 Set-Cookie 標(biāo)頭蹦玫。緩存指示是在該事件觸發(fā)前處理的赎婚,所以修改 Cache-Control 之類的標(biāo)頭不會影響瀏覽器的緩存。它還允許您重定向請求樱溉。

onAuthRequired(可以為同步)

當(dāng)請求需要用戶認證時產(chǎn)生挣输。這一事件可以同步處理,提供認證憑據(jù)福贞。注意撩嚼,擴展程序提供的憑據(jù)可能無效,注意不要重復(fù)提供無效憑據(jù),陷入無限循環(huán)完丽。

onBeforeRedirect

當(dāng)重定向即將執(zhí)行時產(chǎn)生恋技,重定向可以由 HTTP 響應(yīng)代碼或擴展程序觸發(fā)。這一事件僅用于提供信息逻族,并以異步方式處理蜻底,不允許修改或取消請求。

onResponseStarted

當(dāng)接收到響應(yīng)正文的第一個字節(jié)時產(chǎn)生聘鳞。對于 HTTP 請求薄辅,這意味著狀態(tài)行和響應(yīng)標(biāo)頭已經(jīng)可用。這一事件僅用于提供信息抠璃,并以異步方式處理站楚,不允許修改或取消請求。

onCompleted

當(dāng)請求成功處理后產(chǎn)生鸡典。

onErrorOccurred

當(dāng)請求不能成功處理時產(chǎn)生源请。
網(wǎng)絡(luò)請求 API 保證對于每一個請求,onCompleted 或 onErrorOccurred 是最終產(chǎn)生的事件彻况,除了如下例外:如果請求重定向至 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纽甘,大家可以看到代碼中良蛮,每當(dāng)接收到 HTTP(S) 響應(yīng)標(biāo)頭時,將會獲取到其中的responseHeaders悍赢,然后將其中的‘x-frame-options’這個設(shè)置給砍掉决瞳。這樣瀏覽器的最終結(jié)果就成功繞過了iframe的設(shè)置,強行的將網(wǎng)頁變成內(nèi)嵌的iframe左权。
至于瀏覽器的安全問題皮胡。。赏迟。屡贺。。
锌杀。甩栈。
你都裝了這么流氓的插件了,我們網(wǎng)站能咋辦糕再,自己背鍋量没。

文章資料來源
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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市突想,隨后出現(xiàn)的幾起案子殴蹄,更是在濱河造成了極大的恐慌究抓,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件饶套,死亡現(xiàn)場離奇詭異漩蟆,居然都是意外死亡垒探,警方通過查閱死者的電腦和手機妓蛮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來圾叼,“玉大人蛤克,你說我怎么就攤上這事∫奈茫” “怎么了构挤?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長惕鼓。 經(jīng)常有香客問我筋现,道長,這世上最難降的妖魔是什么箱歧? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任矾飞,我火速辦了婚禮,結(jié)果婚禮上呀邢,老公的妹妹穿的比我還像新娘洒沦。我一直安慰自己,他們只是感情好价淌,可當(dāng)我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布申眼。 她就那樣靜靜地躺著,像睡著了一般蝉衣。 火紅的嫁衣襯著肌膚如雪括尸。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天病毡,我揣著相機與錄音濒翻,去河邊找鬼。 笑死剪验,一個胖子當(dāng)著我的面吹牛肴焊,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播功戚,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼娶眷,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了啸臀?” 一聲冷哼從身側(cè)響起届宠,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤烁落,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后豌注,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體伤塌,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年轧铁,在試婚紗的時候發(fā)現(xiàn)自己被綠了每聪。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡齿风,死狀恐怖药薯,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情救斑,我是刑警寧澤童本,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站脸候,受9級特大地震影響穷娱,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜运沦,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一泵额、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧茶袒,春花似錦梯刚、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至向叉,卻和暖如春锥腻,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背母谎。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工瘦黑, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人奇唤。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓幸斥,卻偏偏與公主長得像,于是被迫代替她去往敵國和親咬扇。 傳聞我的和親對象是個殘疾皇子甲葬,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,614評論 2 353

推薦閱讀更多精彩內(nèi)容

  • 原文地址:原文地址 什么是跨域? 跨域是指一個域下的文檔或腳本試圖去請求另一個域下的資源懈贺,這里跨域是廣義的经窖。 廣義...
    C_Y大漁閱讀 1,259評論 1 13
  • 什么是跨域坡垫? 2.) 資源嵌入:、画侣、冰悠、等dom標(biāo)簽,還有樣式中background:url()配乱、@font-fac...
    電影里的夢i閱讀 2,372評論 0 5
  • 什么是跨域 跨域溉卓,是指瀏覽器不能執(zhí)行其他網(wǎng)站的腳本。它是由瀏覽器的同源策略造成的宪卿,是瀏覽器對JavaScript實...
    HeroXin閱讀 836評論 0 4
  • 什么是跨域 跨域的诵,是指瀏覽器不能執(zhí)行其他網(wǎng)站的腳本万栅。它是由瀏覽器的同源策略造成的佑钾,是瀏覽器對JavaScript實...
    Yaoxue9閱讀 1,299評論 0 6
  • 12月9日,2016中國國際智慧教育展覽會在國家會議中心舉行烦粒。展會以“智慧+教育跨界新融合”為主題休溶,通過教育信息化...
    因酷時代閱讀 163評論 0 0