跨站腳本攻擊(Cross Site Scripting),為不和層疊樣式表(Cascading Style Sheets, CSS)的縮寫混淆,故將跨站腳本攻擊縮寫為XSS。
這里我們分上下文來形成一個防御的解決方案,雖然說在某些特殊情況下依然可能會產生XSS,但是如果嚴格按照此解決方案則能避免大部分XSS攻擊。
原則:寧死也不讓數據變成可執行的代碼,不信任任何用戶的數據,嚴格區分數據和代碼。
XSS 的攻擊原理這里不再闡述,詳情請移步 WIKI百科 或 百度百科。
既然是將數據給注入到代碼里面變成可執行代碼,那么我們就找出所有可能的地方,絕大多數XSS發生在MVC模式里面View層。
我們來看看過程。
其中:A B C D E F 標記的地方則代表可能會產生XSS
我們分不同上下文來進行不同的編碼函數,就可以很肯定的斷絕在這些地方產生XSS,只要情況不特殊(特殊如:寬字節 base64編碼等),就一定可以保證安全。
術語(必讀):
下文會用到 JavascriptEncode ,CSSEncode ,HTMLEncode ,URLEncode 等術語,這不是一個某種語言里面的內置函數,而是一種函數的實現,可以將某些數據轉義成特定語言的數據
如 HTMLEncode 函數實現應該至少進行 & < > " ' / 等符號轉義成 & < > " ' /
A: 后端》》》》》》CSS
輸出到CSS通常不會出現什么XSS,但是如果CSS里面有可能的用戶完全可以控制的變量,如果我可以自定義 style 屬性而且沒過濾,或者可以直接控制某段CSS。
<p style="background-image: url(javascript:alert(/xss/));">
//同理
<style>
#id { background-image: url(javascript:alert(/xss/));}
</style>
這樣就可以利用偽協議來實現。
解決方案:
對style屬性里面的數據進行嚴格的檢查,並且對於用戶輸出到xss里面的內容進行適當的CSS編碼。
B: 后端》》》》》》 Javascript
這種直接輸出的js又不過濾簡直就是老掉牙的xss漏洞。
var x =""; //如果假設用戶可以控制x變量 //那么我輸入 ";alert(/xss/);// //那么這串代碼會變成
var x ="";alert(/xss/);//"; //紅色部分是用戶輸入的字符 //成功彈出 提示框,執行了額外的代碼
當然還有一堆方法實現各種xss,各種姿勢。所以這種是最最最簡單的xss也是最容易被利用的。
解決方法:
對其進行嚴格的JavascriptEncode,將某些字符轉義,如 " 變成 \" ,' 變成 \' 等等(不止這些) 防止用戶逃脫你的 雙(單)引號,也可以防止其他姿勢注入。
C: Javascript》》》》》》生成HTML元素或添加html元素屬性
如 js 給 <div> 添加height 屬性 變成 <div height="200px">
對於這個時候,從js輸出數據到屬性或 innerHTML/document.write 等函數生成任何元素,都要視為一次可能的XSS輸出。因為上下文已經不一樣了,這次JavascriptEncode是不對的。
否則你只能保證數據在js里面不會被注入,而在html的話,就不一定了。
解決方法:
應該使用 HTMLEncode 編碼,保證你從js輸出到HTML的元素和屬性不會脫離你的控制。
D: Javascript》》》》》》輸出到HTML元素里面的事件 或其他任何動態執行js的地方
列如下列一段代碼,如果foo是從js執行之后動態輸出到html里面的。foo是用戶可以控制的。
<script>document.write("<img onload=' " + var + " '>");</script>
<img onload='alert("var");'>
那么我完全可以跟上次一樣,輸入 ";alert(/xss/);//, 即使你第一次從后端到js使用了一次jsEncode,但是很遺憾,輸出到html事件(write函數)后代碼會轉義回來,所以我依然執行了。
則會變成:
<img onload='alert("";alert(/xss/);//");'>
可以看見,當你加載完畢之后,恭喜執行我的惡意代碼。
解決方案:
使用 JavascriptEncode,對事件里面的js代碼進行編碼。這里也必須視為一次可能的XSS輸出。
E:后端 》》》》》》輸出到HTML元素里面的事件 或其他任何動態執行js的地方
列簡直可以視為跟D是一模一樣的,所以你只需要理解D情況,那么這個也就自然可以理解了。
<img onload='var'>
如果var是后端直接未經過處理輸出,則輸入 ';alert(/xss/);// 則觸發XSS
解決方法:
也是對var進行JavascriptEncode。
F:后端 》》》》》》生成HTML元素或添加html元素屬性
與C情況也是一模一樣。只是輸出源不同了而已,原理模式都一樣。
<div> $var </div>
如果$var是后端輸出的,那么我可以輸入<script>alert(/xss/)</script> 或 <img scr='' onerror='alert(/xss/)'>
總之這樣很容易注入XSS
解決方法:
對var變量進行HtmlEncode,那么我就無論如何也構建不了<>任何元素了。也就不可能有<script> 或新建元素利用Onload事件等。
上文總結:
仔細理解一下這些,你就會豁然開朗,總之,數據與代碼要嚴格分離,然后要觀察輸出到哪,輸出的上下文環境是什么。
切記:從一種代碼到另外一種代碼都要視為一次可能出現的XSS,因為原先轉義的字符會在輸出的時候轉義回來.
比如 \" 會變回 ",因為瀏覽器要確保用戶看見的是" 而不是 \",否則業務就錯誤了,你總不想你寫個名字是 Suwings'blog 結果刷新之后變成 Suwings\'blog 吧。。。
感謝你的耐心閱讀,如果喜歡可以推薦一下,或者支持,不足之處還望指正。