2020-05-06

js同源限制

所謂同源指的是“三個相同”

.協(xié)議相同

.域名相同

.端口相同

舉例來說抒钱,http://www.example.com/dir/page.html這個網(wǎng)址悲幅,協(xié)議是http://收苏,域名是www.example.com琅捏,端口是80(默認端口可以省略)逢渔,它的同源情況如下。

http://www.example.com/dir2/other.html:同源
http://example.com/dir/other.html:不同源(域名不同)
http://v2.www.example.com/dir/other.html:不同源(域名不同)
http://www.example.com:81/dir/other.html:不同源(端口不同)
https://www.example.com/dir/page.html:不同源(協(xié)議不同)

目的

同源政策的目的是為了保證用戶信息的安全飞蹂。防止惡意的網(wǎng)站竊取數(shù)據(jù)
設(shè)想這樣一種情況:A 網(wǎng)站是一家銀行几苍,用戶登錄以后,A 網(wǎng)站在用戶的機器上設(shè)置了一個 Cookie陈哑,包含了一些隱私信息(比如存款總額)擦剑。用戶離開 A 網(wǎng)站以后,又去訪問 B 網(wǎng)站芥颈,如果沒有同源限制,B 網(wǎng)站可以讀取 A 網(wǎng)站的 Cookie赚抡,那么隱私信息就會泄漏爬坑。更可怕的是,Cookie 往往用來保存用戶的登錄狀態(tài)涂臣,如果用戶沒有退出登錄盾计,其他網(wǎng)站就可以冒充用戶售担,為所欲為。因為瀏覽器同時還規(guī)定署辉,提交表單不受同源政策的限制族铆。

由此可見,同源政策是必需的哭尝,否則 Cookie 可以共享哥攘,互聯(lián)網(wǎng)就毫無安全可言了。

限制范圍

隨著互聯(lián)網(wǎng)的發(fā)展材鹦,同源政策越來越嚴格逝淹。目前,如果非同源桶唐,共有三種行為受到限制栅葡。

  1. 無法讀取非同源網(wǎng)頁的 Cookie、LocalStorage 和 IndexedDB尤泽。
  2. 無法接觸非同源網(wǎng)頁的 DOM欣簇。
  3. 無法向非同源地址發(fā)送 AJAX 請求(可以發(fā)送,但瀏覽器會拒絕接收響應(yīng))

另外坯约,通過 JavaScript 腳本可以拿到其他窗口的window對象熊咽。如果是非同源的網(wǎng)頁,目前允許一個窗口可以接觸其他網(wǎng)頁的window對象的九個屬性和四個方法:window.closed鬼店、window.frames网棍、window.length、window.location妇智、window.opener滥玷、window.parent、window.self巍棱、window.top惑畴、window.window、window.blur()航徙、window.close()如贷、window.focus()、window.postMessage()到踏。

上面的九個屬性之中杠袱,只有window.location是可讀寫的,其他八個全部都是只讀窝稿。而且楣富,即使是location對象,非同源的情況下伴榔,也只允許調(diào)用location.replace方法和寫入location.href屬性纹蝴。

雖然這些限制是必要的庄萎,但是有時很不方便,合理的用途也受到影響塘安。下面介紹如何規(guī)避上面的限制糠涛。

cookie

Cookie 是服務(wù)器寫入瀏覽器的一小段信息,只有同源的網(wǎng)頁才能共享兼犯。如果兩個網(wǎng)頁一級域名相同忍捡,只是次級域名不同,瀏覽器允許通過設(shè)置document.domain共享 Cookie免都。

舉例來說锉罐,A 網(wǎng)頁的網(wǎng)址是http://w1.example.com/a.html,B 網(wǎng)頁的網(wǎng)址是http://w2.example.com/b.html绕娘,那么只要設(shè)置相同的document.domain脓规,兩個網(wǎng)頁就可以共享 Cookie。因為瀏覽器通過document.domain屬性來檢查是否同源险领。

// 兩個網(wǎng)頁都需要設(shè)置
document.domain = 'example.com';

注意侨舆,A 和 B 兩個網(wǎng)頁都需要設(shè)置document.domain屬性,才能達到同源的目的绢陌。因為設(shè)置document.domain的同時挨下,會把端口重置為null,因此如果只設(shè)置一個網(wǎng)頁的document.domain脐湾,會導(dǎo)致兩個網(wǎng)址的端口不同臭笆,還是達不到同源的目的。
現(xiàn)在秤掌,A 網(wǎng)頁通過腳本設(shè)置一個 Cookie愁铺。

document.cookie = "test1=hello";

B 網(wǎng)頁就可以讀到這個 Cookie。

var allCookie = document.cookie;

注意闻鉴,這種方法只適用于 Cookie 和 iframe 窗口钦购,LocalStorage 和 IndexedDB 無法通過這種方法刹枉,規(guī)避同源政策,而要使用PostMessage API立轧。

另外卷雕,服務(wù)器也可以在設(shè)置 Cookie 的時候注簿,指定 Cookie 的所屬域名為一級域名敢茁,比如.example.com篡帕。

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

這樣的話,二級域名和三級域名不用做任何設(shè)置次询,都可以讀取這個 Cookie腋舌。

iframe 和多窗口通信

iframe元素可以在當(dāng)前網(wǎng)頁之中,嵌入其他網(wǎng)頁渗蟹。每個iframe元素形成自己的窗口块饺,即有自己的window對象。iframe窗口之中的腳本雌芽,可以獲得父窗口和子窗口授艰。但是,只有在同源的情況下世落,父窗口和子窗口才能通信淮腾;如果跨域,就無法拿到對方的 DOM屉佳。

比如谷朝,父窗口運行下面的命令,如果iframe窗口不是同源武花,就會報錯圆凰。

document.getElementById("myIFrame").contentWindow.document
// Uncaught DOMException: Blocked a frame from accessing a cross-origin frame.

上面命令中,父窗口想獲取子窗口的 DOM体箕,因為跨域?qū)е聢箦e专钉。

反之亦然,子窗口獲取主窗口的 DOM 也會報錯累铅。

window.parent.document.body // 報錯

這種情況不僅適用于iframe窗口跃须,還適用于window.open方法打開的窗口,只要跨域娃兽,父窗口與子窗口之間就無法通信菇民。

如果兩個窗口一級域名相同,只是二級域名不同投储,那么設(shè)置document.domain屬性第练,就可以規(guī)避同源政策,拿到 DOM轻要。

對于完全不同源的網(wǎng)站复旬,目前有兩種方法,可以解決跨域窗口的通信問題冲泥。

片段識別符(fragment identifier)
跨文檔通信API(Cross-document messaging)
片段標識符指的是驹碍,URL 的#號后面的部分,比如http://example.com/x.html#fragment的#fragment凡恍。如果只是改變片段標識符志秃,頁面不會重新刷新。

父窗口可以把信息嚼酝,寫入子窗口的片段標識符浮还。

var src = originURL + '#' + data;
document.getElementById('myIFrame').src = src;

上面代碼中,父窗口把所要傳遞的信息闽巩,寫入iframe窗口的片段標識符钧舌。

子窗口通過監(jiān)聽hashchange事件得到通知担汤。

window.onhashchange = checkMessage;

function checkMessage() {
  var message = window.location.hash;
  // ...
}

同樣的,子窗口也可以改變父窗口的片段標識符洼冻。


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

window.postMessage()

上面的這種方法屬于破解崭歧,HTML5 為了解決這個問題,引入了一個全新的API:跨文檔通信 API(Cross-document messaging)撞牢。

這個 API 為window對象新增了一個window.postMessage方法率碾,允許跨窗口通信,不論這兩個窗口是否同源屋彪。舉例來說所宰,父窗口aaa.com向子窗口bbb.com發(fā)消息,調(diào)用postMessage方法就可以了畜挥。

// 父窗口打開一個子窗口
var popup = window.open('http://bbb.com', 'title');
// 父窗口向子窗口發(fā)消息
popup.postMessage('Hello World!', 'http://bbb.com');

postMessage方法的第一個參數(shù)是具體的信息內(nèi)容仔粥,第二個參數(shù)是接收消息的窗口的源(origin),即“協(xié)議 + 域名 + 端口”砰嘁。也可以設(shè)為*件炉,表示不限制域名,向所有窗口發(fā)送矮湘。
子窗口向父窗口發(fā)送消息的寫法類似斟冕。

// 子窗口向父窗口發(fā)消息
window.opener.postMessage('Nice to see you', 'http://aaa.com');

父窗口和子窗口都可以通過message事件,監(jiān)聽對方的消息缅阳。

// 父窗口和子窗口都可以用下面的代碼磕蛇,
// 監(jiān)聽 message 消息
window.addEventListener('message', function (e) {
  console.log(e.data);
},false);

message事件的參數(shù)是事件對象event,提供以下三個屬性十办。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末秀撇,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子向族,更是在濱河造成了極大的恐慌呵燕,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,589評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件件相,死亡現(xiàn)場離奇詭異再扭,居然都是意外死亡,警方通過查閱死者的電腦和手機夜矗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評論 3 396
  • 文/潘曉璐 我一進店門泛范,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人紊撕,你說我怎么就攤上這事罢荡。” “怎么了?”我有些...
    開封第一講書人閱讀 165,933評論 0 356
  • 文/不壞的土叔 我叫張陵区赵,是天一觀的道長惭缰。 經(jīng)常有香客問我,道長笼才,這世上最難降的妖魔是什么从媚? 我笑而不...
    開封第一講書人閱讀 58,976評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮患整,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘喷众。我一直安慰自己各谚,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,999評論 6 393
  • 文/花漫 我一把揭開白布到千。 她就那樣靜靜地躺著昌渤,像睡著了一般。 火紅的嫁衣襯著肌膚如雪憔四。 梳的紋絲不亂的頭發(fā)上膀息,一...
    開封第一講書人閱讀 51,775評論 1 307
  • 那天,我揣著相機與錄音了赵,去河邊找鬼潜支。 笑死,一個胖子當(dāng)著我的面吹牛柿汛,可吹牛的內(nèi)容都是我干的冗酿。 我是一名探鬼主播,決...
    沈念sama閱讀 40,474評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼络断,長吁一口氣:“原來是場噩夢啊……” “哼裁替!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起貌笨,我...
    開封第一講書人閱讀 39,359評論 0 276
  • 序言:老撾萬榮一對情侶失蹤弱判,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后锥惋,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體昌腰,經(jīng)...
    沈念sama閱讀 45,854評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,007評論 3 338
  • 正文 我和宋清朗相戀三年净刮,在試婚紗的時候發(fā)現(xiàn)自己被綠了剥哑。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,146評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡淹父,死狀恐怖株婴,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤困介,帶...
    沈念sama閱讀 35,826評論 5 346
  • 正文 年R本政府宣布大审,位于F島的核電站,受9級特大地震影響座哩,放射性物質(zhì)發(fā)生泄漏徒扶。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,484評論 3 331
  • 文/蒙蒙 一根穷、第九天 我趴在偏房一處隱蔽的房頂上張望姜骡。 院中可真熱鬧,春花似錦屿良、人聲如沸圈澈。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,029評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽康栈。三九已至,卻和暖如春喷橙,著一層夾襖步出監(jiān)牢的瞬間啥么,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,153評論 1 272
  • 我被黑心中介騙來泰國打工贰逾, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留悬荣,地道東北人。 一個月前我還...
    沈念sama閱讀 48,420評論 3 373
  • 正文 我出身青樓似踱,卻偏偏與公主長得像隅熙,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子核芽,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,107評論 2 356