背景
網站中包含大量的動態內容以提高用戶體驗,比過去要複雜得多。所謂動態內容,就是根據用戶環境和需要,Web應用程式能夠輸出相應的內容。動態站點會受到一種名為“跨站腳本攻擊”(Cross Site Scripting, 安全專家們通常將其縮寫成XSS,原本應當是css,但為了和層疊樣式表(Cascading Style Sheet,CSS )有所區分,故稱XSS)的威脅,而靜態站點則完全不受其影響。
簡介
用戶在瀏覽網站、使用
即時通訊軟體、甚至在閱讀電子郵件時,通常會點擊其中的連結。攻擊者通過在連結中插入
惡意代碼,就能夠盜取用戶信息。攻擊者通常會用十六進制(或其他編碼方式)將連結編碼,以免用戶懷疑它的合法性。網站在接收到包含惡意代碼的請求之後會產成一個包含惡意代碼的頁面,而這個頁面看起來就像是那個網站應當生成的合法頁面一樣。許多流行的留言本和論壇程式允許用戶發表包含HTML和javascript的帖子。假設用戶甲發表了一篇包含
惡意腳本的帖子,那么用戶乙在瀏覽這篇帖子時,惡意腳本就會執行,盜取用戶乙的session信息。有關攻擊方法的詳細情況將在下面闡述。
攻擊分類
人們經常將跨站腳本攻擊(Cross Site Scripting)縮寫為CSS,但這會與層疊樣式表(Cascading Style Sheets, CSS)的縮寫混淆。因此有人將跨站腳本攻擊縮寫為XSS。如果你聽到有人說 “我發現了一個XSS漏洞”,顯然他是在說跨站腳本攻擊。
類型
(1)持久型跨站:最直接的危害類型,跨站代碼存儲在
伺服器(資料庫)。(2)非持久型跨站:反射型跨站腳本漏洞,最普遍的類型。用戶訪問伺服器-跨站連結-返回跨站代碼。(3)
DOM跨站(DOM XSS):DOM(document object model文檔對象模型),客戶端腳本處理邏輯導致的安全問題。
危害
為了蒐集用戶信息,攻擊者通常會在有漏洞的程式中插入 JavaScript、VBScript、 ActiveX或Flash以欺騙用戶(詳見下文)。一旦得手,他們可以盜取用戶帳戶,修改用戶設定,盜取/污染cookie,做虛假廣告等。每天都有大量的
XSS攻擊的
惡意代碼出現。 Brett Moore的下面這篇文章詳細地闡述了“
拒絕服務攻擊”以及用戶僅僅閱讀一篇文章就會受到的“自動攻擊”。
三部曲
1.HTML注入。所有HTML注入範例只是注入一個JavaScript彈出式的警告框:alert(1)。
2.做壞事。如果您覺得警告框還不夠刺激,當受害者點擊了一個被注入了HTML代碼的頁面連結時攻擊者能作的各種的惡意事情。
3.誘捕受害者。
攻擊事件
“微博病毒”攻擊事件
回顧:
2011年6月28日晚,新浪微博出現了一次比較大的XSS攻擊事件。大量用戶自動傳送諸如:“郭美美事件的一些未注意到的細節”,“建黨大業中穿幫的地方”,“讓女人心動的100句詩歌”,“3D肉團團高清國語版種子”,“這是傳說中的神仙眷侶啊”,“驚爆!范冰冰艷照真流出了”等等微博和私信,並自動關注一位名為
hellosamy的用戶。
事件的經過線索如下:
20:30,某網站中的病毒頁面無法訪問
20:32,新浪微博中hellosamy用戶無法訪問
21:02,新浪漏洞修補完畢
下一代
隨著
AJAX(Asynchronous JavaScript and XML,異步JavaScript和XML)技術的普遍套用,XSS的攻擊危害將被放大。使用AJAX的最大優點,就是可以不用更新整個頁面來維護數據,Web套用可以更迅速地回響用戶請求。AJAX會處理來自
Web伺服器及源自第三方的豐富信息,這對XSS攻擊提供了良好的機會。AJAX套用架構會泄漏更多套用的細節,如函式和變數名稱、函式參數及返回類型、數據類型及有效範圍等。AJAX套用架構還有著較傳統架構更多的套用輸入,這就增加了可被攻擊的點。
預防
從網站開發者角度,如何防護XSS攻擊?
來自套用安全國際組織OWASP的建議,對XSS最佳的防護應該結合以下兩種方法:驗證所有輸入數據,有效檢測攻擊;對所有輸出數據進行適當的編碼,以防止任何已成功注入的腳本在瀏覽器端運行。具體如下:
輸入驗證:某個數據被接受為可被顯示或存儲之前,使用標準輸入驗證機制,驗證所有輸入數據的長度、類型、語法以及業務規則。
輸出編碼:數據輸出前,確保用戶提交的數據已被正確進行entity編碼,建議對所有字元進行編碼而不僅局限於某個子集。
明確指定輸出的編碼方式:不要允許攻擊者為你的用戶選擇編碼方式(如ISO 8859-1或 UTF 8)。
注意黑名單驗證方式的局限性:僅僅查找或替換一些字元(如"<" ">"或類似"script"的關鍵字),很容易被XSS變種攻擊繞過驗證機制。
警惕規範化錯誤:驗證輸入之前,必須進行解碼及規範化以符合應用程式當前的內部表示方法。請確定應用程式對同一輸入不做兩次解碼。
從網站用戶角度,如何防護XSS攻擊?
當你打開一封Email或附屬檔案、瀏覽論壇帖子時,可能
惡意腳本會自動執行,因此,在做這些操作時一定要特別謹慎。建議在瀏覽器設定中關閉JavaScript。如果使用
IE瀏覽器,將安全級別設定到“高”。具體可以參照瀏覽器安全的相關文章。
這裡需要再次提醒的是,XSS攻擊其實伴隨著社會工程學的成功套用,需要增強安全意識,只信任值得信任的站點或內容。可以通過一些檢測工具進行
xss的漏洞檢測,類似工具有億思網站安全檢測平台。針對xss的漏洞帶來的危害是巨大,如有發現,應立即修復漏洞。
XSS防禦規則
下列規則旨在防止所有發生在應用程式的XSS攻擊,雖然這些規則不允許任意向HTML文檔放入不可信數據,不過基本上也涵蓋了絕大多數常見的情況。你不需要採用所有規則,很多企業可能會發現第一條和第二條就已經足以滿足需求了。請根據自己的需求選擇規則。
No.1
– 不要在允許位置插入不可信數據
第一條規則就是拒絕所有數據,不要將不可信數據放入HTML文檔,除非是下列定義的插槽。這樣做的理由是在理列有解碼規則的HTML中有很多奇怪的context,讓事情變得很複雜,因此沒有理由將不可信數據放在這些context中。
<script>...NEVERPUTUNTRUSTEDDATAHERE...</script> directlyinascript
<!--...NEVERPUTUNTRUSTEDDATAHERE...--> insideanHTMLcomment
<div...NEVERPUTUNTRUSTEDDATAHERE...=test/> inanattributename
<...NEVERPUTUNTRUSTEDDATAHERE...href="/test"/> inatagname
更重要的是,不要接受來自不可信任來源的JavaScript代碼然後運行,例如,名為“callback”的參數就包含JavaScript代碼段,沒有解碼能夠解決。
No.2
– 在向HTML元素內容插入不可信數據前對HTML解碼
這條規則適用於當你想把不可信數據直接插入HTML正文某處時,這包括內部正常標籤(div、p、b、td等)。大多數網站框架都有HTML解碼的方法且能夠躲開下列字元。但是,這對於其他HTML context是遠遠不夠的,你需要部署其他規則。
<body>...ESCAPEUNTRUSTEDDATABEFOREPUTTINGHERE... </body>
<div>...ESCAPEUNTRUSTEDDATABEFOREPUTTINGHERE...</div>
以及其他的HTML常用元素
使用HTML實體解碼躲開下列字元以避免切換到任何執行內容,如腳本、樣式或者事件處理程式。在這種規格中推薦使用十六進制實體,除了XML中5個重要字元(&、<、 >、 "、 ')外,還加入了斜線符,以幫助結束HTML實體。
&-->&
<--><
>-->>
"-->"
'-- >''isnotrecommended
/-- >/forwardslashisincludedasithelpsendanHTMLentity
No.3
– 在向HTML常見屬性插入不可信數據前進行屬性解碼
這條規則是將不可信數據轉化為典型屬性值(如寬度、名稱、值等),這不能用於複雜屬性(如href、src、style或者其他事件處理程式)。這是及其重要的規則,事件處理器屬性(為HTML JavaScript Data Values)必須遵守該規則。
<divattr=...ESCAPEUNTRUSTEDDATABEFOREPUTTINGHERE...>content</div> insideUNquotedattribute
<divattr='...ESCAPEUNTRUSTEDDATABEFOREPUTTINGHERE...'>content</div> insidesinglequotedattribute
<divattr="...ESCAPEUNTRUSTEDDATABEFOREPUTTINGHERE...">content</div> insidedoublequotedattribute
除了字母數字字元外,使用小於256的ASCII值&#xHH格式(或者命名的實體)對所有數據進行解碼以防止切換屬性。這條規則套用廣泛的原因是因為開發者常常讓屬性保持未引用,正確引用的屬性只能使用相應的引用進行解碼。未引用屬性可以被很多字元破壞,包括[space] % * + , - / ; < = > ^ 和 |。
No.4
– 在向HTML JavaScript Data Values插入不可信數據前,進行JavaScript解碼
這條規則涉及在不同HTML元素上制定的JavaScript事件處理器。向這些事件處理器放置不可信數據的唯一安全位置就是“data value”。在這些小代碼塊放置不可信數據是相當危險的,因為很容易切換到執行環境,因此請小心使用。
<script>alert('...ESCAPEUNTRUSTEDDATABEFOREPUTTINGHERE...')</script> insideaquotedstring
<script>x=...ESCAPEUNTRUSTEDDATABEFOREPUTTINGHERE...</script> onesideofanexpression
<divonmouseover=...ESCAPEUNTRUSTEDDATABEFOREPUTTINGHERE...</div> insideUNquotedeventhandler
<divonmouseover='...ESCAPEUNTRUSTEDDATABEFOREPUTTINGHERE...'</div> insidequotedeventhandler
<divonmouseover="...ESCAPEUNTRUSTEDDATABEFOREPUTTINGHERE..."</div> insidequotedeventhandler
除了字母數字字元外,使用小於256的ASCII值xHH格式 對所有數據進行解碼以防止將數據值切換至腳本內容或者另一屬性。不要使用任何解碼捷徑(如" )因為引用字元可能被先運行的HTML屬性解析器相匹配。如果事件處理器被引用,則需要相應的引用來解碼。這條規則的廣泛套用是因為開發者經常讓事件處理器保持未引用。正確引用屬性只能使用相應的引用來解碼,未引用屬性可以使用任何字元(包括[space] % * + , - / ; < = > ^ 和|)解碼。同時,由於HTML解析器比JavaScript解析器先運行,關閉標籤能夠關閉腳本塊,即使腳本塊位於引用字元串中。
No.5
– 在向HTML 樣式屬性值插入不可信數據前,進行CSS解碼
當你想將不可信數據放入樣式表或者樣式標籤時,可以用此規則。CSS是很強大的,可以用於許多攻擊。因此,只能在屬性值中使用不可信數據而不能在其他樣式數據中使用。不能將不可信數據放入複雜的屬性(如url,、behavior、和custom (-moz-binding))。同樣,不能將不可信數據放入允許JavaScript的IE的expression屬性值。
<style>selector{property:...ESCAPEUNTRUSTEDDATABEFOREPUTTINGHERE...;}</style> propertyvalue
<spanstyle=property:...ESCAPEUNTRUSTEDDATABEFOREPUTTINGHERE...;>text</style> propertyvalue
除了字母數字字元外,使用小於256的ASCII值HH格式對所有數據進行解碼。不要使用任何解碼捷徑(如" )因為引用字元可能被先運行的HTML屬性解析器相匹配,防止將數據值切換至腳本內容或者另一屬性。同時防止切換至expression或者其他允許腳本的屬性值。如果屬性被引用,將需要相應的引用進行解碼,所有的屬性都應該被引用。未引用屬性可以使用任何字元(包括[space] % * + , - / ; < = > ^ 和|)解碼。同時,由於HTML解析器比JavaScript解析器先運行,</script>標籤能夠關閉腳本塊,即使腳本塊位於引用字元串中。
No.6
- 在向HTML URL屬性插入不可信數據前,進行URL解碼
當你想將不可信數據放入連結到其他位置的link中時需要運用此規則。這包括href和src屬性。還有很多其他位置屬性,不過我們建議不要在這些屬性中使用不可信數據。需要注意的是在javascript中使用不可信數據的問題,不過可以使用上述的HTML JavaScript Data Value規則。
<ahref=http://...ESCAPEUNTRUSTEDDATABEFOREPUTTINGHERE...>link</a> anormallink
<imgsrc='http://...ESCAPEUNTRUSTEDDATABEFOREPUTTINGHERE...'/> animagesource
<scriptsrc="http://...ESCAPEUNTRUSTEDDATABEFOREPUTTINGHERE..."/> ascriptsource
除了字母數字字元外,使用小於256的ASCII值%HH 解碼格式對所有數據進行解碼。在數據中保護不可信數據:URL不能夠被允許,因為沒有好方法來通過解碼來切換URL以避免攻擊。所有的屬性都應該被引用。未引用屬性可以使用任何字元(包括[space] % * + , - / ; < = > ^ 和|)解碼。 請注意實體編碼在這方面是沒用的。