如今的WEB標(biāo)準(zhǔn)紛繁復(fù)雜翠储,在瀏覽稍大一些的網(wǎng)站時(shí)绘雁,細(xì)心的人會(huì)發(fā)現(xiàn)網(wǎng)頁(yè)上呈現(xiàn)的內(nèi)容并不僅限于網(wǎng)站自身提供的內(nèi)容,而是來(lái)自一堆五花八門(mén)的網(wǎng)站的內(nèi)容的集合援所。但有誰(shuí)會(huì)想到同源策略在保護(hù)著網(wǎng)民們的安全呢庐舟?
了解同源策略是十分有必要的,要深入掌握XSS / CSRF等WEB安全漏洞住拭,不了解同源策略就如同盲人摸象一般挪略,無(wú)法說(shuō)出全貌,更無(wú)法應(yīng)用其進(jìn)行打擊滔岳。另外,無(wú)論是網(wǎng)銀盜號(hào)杠娱,還是隱私泄露,理解了同源策略谱煤,就有助于理解自己面臨著什么樣的威脅摊求。
0x00 什么是源和同源策略
源就是主機(jī),協(xié)議刘离,端口名的一個(gè)三元組室叉。
同源策略(Same Origin Policy, SOP)是Web應(yīng)用程序的一種安全模型,它控制了網(wǎng)頁(yè)中DOM之間的訪問(wèn)硫惕。重要的事情說(shuō)三遍茧痕,它只是個(gè)模型,而不是標(biāo)準(zhǔn)(哪怕標(biāo)準(zhǔn)在實(shí)現(xiàn)的時(shí)候也會(huì)千差萬(wàn)別)恼除。同源策略被廣泛地應(yīng)用在處理WEB內(nèi)容的各種客戶端上凿渊,比如各大瀏覽器,微軟的Silverlight缚柳,Adobe的Flash/Acrobat等等埃脏。SOP影響范圍包括:普通的HTTP請(qǐng)求、XMLHttpRequest秋忙、XSLT彩掐、XBL。
0x01 如何判斷同源
定義:如果兩個(gè)頁(yè)面的協(xié)議灰追,端口(如果有指定)和主機(jī)都相同堵幽,則兩個(gè)頁(yè)面具有相同的源。我們也可以把它稱為“協(xié)議/主機(jī)/端口 tuple”弹澎,或簡(jiǎn)單地叫做“tuple". ("tuple" 朴下,“元”,是指一些事物組合在一起形成一個(gè)整體苦蒿,比如(1殴胧,2)叫二元,(1,2团滥,3)叫三元)
下表給出了相對(duì)http://store.company.com/dir/page.html同源檢測(cè)的示例:
0x02 同源策略究竟限制了什么竿屹?
首先,我們要明確同源策略只作用在實(shí)現(xiàn)了同源策略的WEB客戶端上灸姊。 雖然筆者不常用百度拱燃,但是我們來(lái)看一個(gè)具有誤導(dǎo)性的結(jié)論:百度詞條對(duì)于同源策略的解釋說(shuō)“只有和目標(biāo)同源的腳本才會(huì)被執(zhí)行”,這是不對(duì)的力惯,同源策略沒(méi)有禁止腳本的執(zhí)行碗誉,而是禁止讀取HTTP回復(fù)。 更正了這個(gè)概念之后父晶,我們會(huì)發(fā)現(xiàn)诗充,SOP其實(shí)在防止CSRF上作用非常有限,CSRF的請(qǐng)求往往在發(fā)送出去的那一瞬間就已經(jīng)達(dá)到了攻擊的目的诱建,比如發(fā)送了一段敏感數(shù)據(jù),或請(qǐng)求了一個(gè)具體的功能碟绑,是否能讀取回復(fù)并不那么重要(唯一的作用是可以防止CSRF請(qǐng)求讀取異源的授權(quán)Token)俺猿。 另外,一般靜態(tài)資源通常不受同源策略限制格仲,如js/css/jpg/png等押袍。
0x03 跨源的網(wǎng)絡(luò)訪問(wèn)
為什么要起這么拗口的名字:網(wǎng)絡(luò)訪問(wèn)?因?yàn)閃EB上資源訪問(wèn)的多樣性凯肋,不能簡(jiǎn)單的稱之為網(wǎng)絡(luò)請(qǐng)求谊惭。大體看來(lái)我們有三種類(lèi)型:
跨域?qū)懀ǔ1辉试S侮东,例如鏈接圈盔,重定向和表單提交,一些不常見(jiàn)的HTTP請(qǐng)求方法例如PUT,DELETE等需要先發(fā)送預(yù)請(qǐng)求(preflight)悄雅,例如發(fā)送OPTIONS來(lái)查詢可用的方法驱敲。
跨域嵌入,通常被允許宽闲。
跨域讀众眨,通常被禁止,然而容诬,我們可以用其他方法達(dá)到讀取的效果娩梨。
一個(gè)經(jīng)久不衰的BUG
早在2011年,一個(gè)用戶在Mozilla的Bug追蹤系統(tǒng)中就提交了一個(gè)issue览徒,聲稱他可以判定某個(gè)網(wǎng)站的訪客是否登錄了gmail,facebook等等狈定。
嵌入iframe來(lái)獲取一個(gè)訪問(wèn)網(wǎng)站的用戶是否登陸了gmail:
<img style="display:none;"
onload="logged_in_to_gmail()"
onerror="not_logged_in_to_gmail()"
src="https://mail.google.com/mail/photos/img/photos/public/AIbEiAIAAABDCKa_hYq24u2WUyILdmNhcmRfcGhvdG8qKDI1ODFkOGViM2I5ZjUwZmZlYjE3MzQ2YmQyMjAzMjFlZTU3NjEzOTYwAZwSCm_MMUDjh599IgoA2muEmEZD"
/>
src的代碼試圖訪問(wèn)一張gmail中攻擊者上傳的圖片,如果用戶沒(méi)有登陸gmail习蓬,就無(wú)法成功加載掸冤。從而達(dá)到判斷用戶是否登陸gmail的效果厘托。這種方法可以推廣到任何對(duì)不應(yīng)跨源訪問(wèn)的資源沒(méi)有正確設(shè)置同源策略的網(wǎng)站。
0x04 談?wù)劰?/strong>
作為一個(gè)抽象的WEB安全模型稿湿,每個(gè)處理WEB內(nèi)容的客戶端實(shí)現(xiàn)的都不完全一樣铅匹,這就帶來(lái)了許多差異點(diǎn),而差異點(diǎn)的存在就帶來(lái)了漏洞饺藤,正所謂“千里之堤包斑,潰于蟻穴”。
對(duì)URI的解析
IP是URI的重要組成部分涕俗,如果留心了RFC的人就會(huì)知道罗丰,IP不止有一種格式。下面的標(biāo)注形式其實(shí)都代表了同一個(gè)IP:216.58.209.68再姑,大家可以在瀏覽器里實(shí)驗(yàn)萌抵。
216.58.53572
0xD8.072.53572
3627733316
0330.3854660
當(dāng)某些瀏覽器對(duì)URI的解釋存在漏洞的時(shí)候,就可以構(gòu)造出有趣的攻擊鏈來(lái)繞過(guò)SOP元镀。 比如CVE-2015-7188火狐瀏覽器SOP繞過(guò)中绍填。攻擊者構(gòu)造了特殊的URL,并在攻擊者自己控制的來(lái)自37.187.18.85的網(wǎng)頁(yè)中發(fā)起跨域請(qǐng)求
先通過(guò)B讓Firefox認(rèn)為這個(gè)請(qǐng)求是請(qǐng)求37.187.18.85本身的內(nèi)容栖疑,再通過(guò)類(lèi)似@字符的Unicode字符@(uFF20)讓瀏覽器認(rèn)為@之前的字符都是translate.google.com的賬號(hào)和密碼讨永,從而返回translate.google.com的網(wǎng)頁(yè)內(nèi)容,實(shí)現(xiàn)繞過(guò)SOP遇革。
設(shè)計(jì)缺陷導(dǎo)致SOP繞過(guò)
在Java6卿闹,7中,如果兩個(gè)域名解析到相同的IP萝快,則會(huì)認(rèn)為他們同源锻霎。假設(shè)我們有attacker.com和victim.com,兩者都共享主機(jī)123.123.123.123。攻擊者attacker.com可以在自己控制的域名下上傳一個(gè)jar文件來(lái)訪問(wèn)victim.com的內(nèi)容揪漩。
訪問(wèn)本地文件的同源策略
不同的瀏覽器使用不同的瀏覽器引擎量窘,而不同的引擎對(duì)于同源策略的處理也并非完全一致。例如氢拥,F(xiàn)irefox使用Gecko瀏覽器引擎蚌铜,在古老的Gecko1.8版(Firefox3)之前,任意兩個(gè)file://的URI都被認(rèn)為是同源的嫩海,意思就是冬殃,任意本地HTML文件將有權(quán)限訪問(wèn)本地計(jì)算機(jī)上任意其他文件。如今的Gecko版本中叁怪,一個(gè)HTML文檔只能訪問(wèn)其所在文件夾下的其他文件审葬。 對(duì)于跨越窗口的DOM訪問(wèn),每個(gè)文件被當(dāng)作一個(gè)單獨(dú)的源,除了一種情況:當(dāng)一個(gè)文件被另一個(gè)文件可以用同源策略訪問(wèn)時(shí)涣觉,視為相同的源痴荐。
<!-- 文件路徑:/home/user/1.html -->
<html>
<frameset cols="50%,*">
<frame src="/home/user/dir/2.html">
<frame src="...">
</frameset>
</html>
上圖中,1.html和2.html被視為相同的源官册。
<!-- 文件路徑:/home/user/dir/1.html -->
<html>
<frameset cols="50%,*">
<frame src="/home/user/2.html">
<frame src="...">
</frameset>
</html>
上圖中生兆,1.html和2.html被視為異源。
特立獨(dú)行的Internet Explorer
在IE中膝宁,有兩種情況同源策略無(wú)效:
TrustZones(信任域):當(dāng)一個(gè)URI被加入到了IE的信任網(wǎng)站區(qū)域中時(shí)鸦难,瀏覽器會(huì)無(wú)視同源策略。
IE在考慮同源策略時(shí)不包括端口员淫, 這意味著不同端口上的應(yīng)用程序可以讀取到比如用戶的登陸賬戶密碼/cookie等合蔽。
通過(guò)變更自身的源繞過(guò)同源策略
IE 6,7版中網(wǎng)頁(yè)可以通過(guò)document.domain設(shè)置自身的來(lái)源為任意其他來(lái)源介返。如今網(wǎng)頁(yè)仍然可以更改源拴事,但是有一些限制。
網(wǎng)頁(yè)可以變更自身的源為父級(jí)域名圣蝎。
例如http://malicious.eth.space/1.html可以通過(guò)執(zhí)行
document.domain = "eth.space";
來(lái)繞過(guò)同源策略的限制刃宵,從而可以讀取http://eth.space/login.html上的內(nèi)容。這其中的應(yīng)用大家可以自己去想捅彻。
注意端口不同的情況。
需要注意的是鞍陨,在改變?cè)磿r(shí)步淹,端口號(hào)是需要特別指定的。由于運(yùn)行以下js代碼
document.domain = document.domain
將會(huì)導(dǎo)致端口號(hào)被重置為null诚撵。所以源http://eth.space:1337不能通過(guò)修改document.domain="eth.space"來(lái)訪問(wèn)http://eth.space的數(shù)據(jù)缭裆,除非后者也設(shè)置了document.domain="eth.space",這樣雙方的源端口號(hào)才能一致(null)。反之亦然寿烟。
0x05 談?wù)劮烙?/strong>
如何安全地允許跨源訪問(wèn)澈驼?
最好的方式是使用CORS,跨源資源共享機(jī)制筛武。這個(gè)需要的篇幅挺大缝其,我們有機(jī)會(huì)下次講。
使用Window.postMessage
使用JSONP徘六。
如何禁止(你的資源被)跨源訪問(wèn)内边?
為了禁止跨域?qū)懀覀冃枰隒SRF令牌待锈,然而我們需要正確的配置同源策略漠其,否則CSRF令牌本身也將被惡意網(wǎng)頁(yè)讀取。
為了禁止跨域讀,我們可以通過(guò)設(shè)置X-Frame-Options頭來(lái)禁止該頁(yè)面被嵌入到惡意頁(yè)面中和屎,就如同在“經(jīng)久不衰的BUG”中一樣拴驮。
為了禁止跨域嵌入,確保你的資源本身無(wú)法嵌入到各種跨域訪問(wèn)方式中柴信,比如<script src=></script> <img src=x></img>套啤,<svg onload=>,各種字體加載等等颠印。同時(shí)纲岭,使用CSRF令牌也可以有效避免被跨域嵌入。
如何禁止你控制的網(wǎng)頁(yè)中嵌入的iFrame做出惡意行為线罕?
使用HTML5的沙盒iframe止潮。
先寫(xiě)到這里吧,事實(shí)上钞楼,WEB安全中還有幾個(gè)重要的機(jī)制喇闸,例如和同源策略相輔相成的跨域資源共享機(jī)制(CORS),和內(nèi)容安全策略(Content Security Policy, CSP)下次再寫(xiě)询件。
文章參考于:
1.https://eth.space/same-origin-policy-101/
2.https://developer.mozilla.org/zh-CN/docs/Web/Security/Same-origin_policy
3.書(shū)籍《白帽講web安全》(如有需要請(qǐng)私自聯(lián)系)