XSS的類型:反射型XSS、存儲型XSS、DOM型XSS
跨站點腳本防範的基本原則:
- 一切的輸入/輸出都是有害的,不要信任任何輸入/輸出數據。
- 所有傳遞過程都不能保障無侵入,執行前、存儲前、顯示前都要進行“數據清潔”。
- 所有的數據校驗、處理工作要在前端和服務器端兩次進行。
- 目前所有的XSS通過com.keegoo.core.util.XSSUtil來過濾。
DOM-based XSS的防範當操作頁面中DOM對象的時候,要對其輸入的參數進行處理,防止XSS的注入。可採用escape、encodeURI、encodeURIComponent或自定義方法進行處理。示例:
Window.location=encodeURI(”http://www.dhgate.com”);
對輸入/輸出進行Encode 將輸入/輸出進行轉義成HTML實體編碼(ISO 8859-1 Latin1)或其他編碼,使得其在瀏覽器中不可自動執行。
不要在html元素和屬性中使用未經轉義的不安全內容。如下面的示例:
<script>...NEVER PUT UNTRUSTED DATA HERE...</script>
directly in a script
<!--...NEVER PUT UNTRUSTED DATA HERE...-->
inside an HTML comment
<div ...NEVER PUT UNTRUSTED DATA HERE...=test />
in an attribute name
<NEVER PUT UNTRUSTED DATA HERE... href="/test" />
in a tag name
<div attr=...ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE...>content</div>
inside UNquoted attribute
<div attr='...ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE...'>content</div>
inside single quoted attribute
<div attr="...ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE...">content</div>
inside double quoted attribute
HttpOnly
(1) 瀏覽器禁止頁面的JavaScript訪問帶有HttpOnly屬性的Cookies。
(2) 添加HttpOnly的過程簡單,效果明顯,有如四兩撥千斤。已成爲一種“標準”做法。
(3) 但在部署時需注意,若業務非常複雜,則需要在所有Set-Cookies的地方,給關鍵的Cookies都加上HttpOnly,漏掉任一地方,都可能使得方案失效。
(4) Apache支持一個Header的TRACE,TRACE一般用於調試,它會將請求頭作爲HTTP Response Body返回。漏洞也修復。
輸入檢查
(1) 輸入的檢查的邏輯,必須放在服務器端代碼中實現,若只在客戶端使用JavaScript中設置輸入檢查,是很容易被攻擊者繞過的。
(2) 這種輸入檢查的方式,可以稱爲“XSS Filter”
輸出檢查
(1) 安全的編碼函數
- 要求使用JavascriptEncode的變量輸入一定要在引號內
如var y = ‘”’+escapeJavascript($evil)+’”’
- 若開發者沒有此習慣,則只能使用改一個更加嚴格的JavascriptEncode函數來保證安全--除了數字、字母外的所有字符,都是用十六進制“\xHH”的方式進行編碼。
- 需要注意的是,編碼後的數據長度可能會發生改變,從而影響某些功能。再寫代碼市需要注意這個細節,以免產生不必要的bug。
(2) 只需要一種編碼嗎
- XSS攻擊主要發生在MVC架構中的View層。大部分的XSS漏洞可以在模版系統中解決.
- 需要區分輸出變量的語境,並非在模版引擎中使用auto-escape就萬事大吉了(比如:對於瀏覽器來說,htmlparser會優先於JavaScript Parser執行,所以解析的過程是HtmlEncode的字符先被解碼,然後執行JavaScript事件)
註釋:
escape()和unescape()是一對編碼解碼函數,一般用於URL中非ASCII字符的編碼和解碼!如:escape("&")返回%26,unescape("%26")返回&,都用十六進制編碼!
MVC全名是Model View Controller,是模型(model)-視圖(view)-控制器(controller)的縮寫
正確的防禦XSS
(1) XSS本質是一種”HTML注入”,用戶的數據本當成了HTML代碼中的一部分來執行,從而混淆了原本的語義,產生了新的語義。
(2) 如果網站使用了MVC架構,那麼XSS就發生在View層—在應用拼接變量到HTML頁面時產生。
(3) 在用戶提交數據處進行輸入檢測的方案,其實並不是在真正發生攻擊的地方做防禦。
(4) 在HTML標籤中輸出
- 在所有標籤中輸出的變量,如果未做任何處理,都能導致直接產生XSS。
- 防禦方法是對變量使用HtmlEncode(HtmlEncode:是將html源文件中不容許出現的字符進行編碼,通常是編碼以下字符:"<"、">"、"&"、"""、"'"等;)
(5) 在HTML屬性中輸出
- OWASP ESAPI中推薦了一種更爲嚴格的HtmlEncode—除了字母、數字外,其他所有的特殊字符都被編碼成HTMLEntities
String safe = ESAPI.encoder().encodeForHTMLAttribute(request.getParameter(“input”));
這種嚴格的編碼方式,可以保證不會出現任何的安全問題
(6) 在<script>標籤中輸出
- 在<script>標籤中輸出時,首先應該確保輸出的變量在引號中
- 攻擊者需要先閉合引號才能實施XSS攻擊
- 防禦時使用JavascriptEncode
(7) 在事件中輸出
- 與<script>標籤類似
- 防禦時使用JavascriptEncode
(8) 在CSS中輸出
- 儘可能禁止用戶可控制的變量在“<style>標籤”、“HTML標籤的style屬性”以及“CSS文件”中輸出
- 如果一定有這樣的需求,推薦使用OWASP ESAPI中的encodeForCSS()函數。
- 其實現原理類似於ESAPI.encoder().encodeForJavaScript()函數,除了字母、數字外的所有字符被編碼成十六進制形式“\uHH”
防禦DOM Based XSS
(1) 事實上,DOM Based XSS是從JavaScript中輸出數據到HTMNL頁面裏
(2) 從JavaScript輸出到HTML頁面,也相當於一次XSS輸出的過程,需要分語境使用不同的編碼函數。
Document.write輸出到HTML頁面時,
如果是輸出到事件或腳本,則要再做一次javascriptEncode,
如果是輸出到HTML內容或者屬性,則要做一次HtmlEncode
(3) 會觸發DOM Based XSS的地方有很多,以下幾個地方是JavaScript輸出到HTML頁面的必經之路
- document.write()
- document.writeln()
- xxx.innerHTML =
- xxx.outerHTML =
- innerHTML.replace
- document.attachEvent()
- window.attachEvent()
- document.location.replace()
- document.location.assign()
- ……
需要重點關注這幾個地方的參數是否可以被用戶控制
(4) 除了服務端直接輸出變量到JavaScript外,還有以下一個地方可能會成爲DOM Based XSS的輸入點,也需要重點關注
- 頁面中所有的inputs框
- window.location(href、hash等)
- window.name
- document.referrer
- document.cookies
- localstorage
- XML HttpRequest返回的數據
(5) 安全研究者Stefano Di Paola設立了一個DOM Based XSS的cheatsheet,地址如下:http://code.google.com/p/domxsswiki
換個角度看XSS風險
(1) 存儲型XSS可能會繞過些檢查工具(如IE8的XSS Filter,firefox的Noscript Extension都會檢查地址欄中的地址是否包含XSS腳本)
(2) 從攻擊過程來說,存儲型XSS 風險頗高
(3) 從風險角度看,互動的頁面是可能發起XSS Worm攻擊的地方
(4) 從業務風險的角度來重新定位每個XSS漏洞,具有更重要的意義。(比如:在網站首頁發生的XSS攻擊要比網站的合作伙伴頁面的XSS攻擊要嚴重的多)