在我上一篇《前端安全之XSS攻擊》文中,並無把XSS攻擊的解決辦法說完整,而XSS的攻擊又那麼五花八門,有沒有一招「獨孤九劍」可以抗衡,畢竟那麼多狀況場景,開發人員沒法一一照顧過來,而今天經過閱讀《白帽子講Web安全》這本書,對應對方式有了更好的總結,分爲兩類,一是服務端能夠乾的事,二是客戶端能夠乾的事。html
前提前端
在說XSS解決方式時,有一個前提。就是同源策略——瀏覽器的同源策略(瀏覽器安全的基礎,即便是攻擊腳本也要遵照這法則),限制了來自不一樣源的「document」或腳本,對當前「document」讀取或設置某些屬性。除了DOM、Cookie、XMLHttpRequest會受到同源策略的限制外,瀏覽器加載的一些第三方插件也有各自的同源策略。不過script、img、iframe、link等標籤均可以跨域加載資源,而不受同源策略的限制。jquery
服務端能夠乾的事後端
1. HttpOnly跨域
其實就是如今HTTP協議(HTTPS也是能夠的)才能讀取cookies,JavaScript是讀取不到cookies的。支持瀏覽器是IE6+、Firefox2+、Google、Safari4+。瀏覽器
JavaEE給Cookie添加HttpOnly的代碼:安全
response.setHeader("Set-Cookie","cookiename=value; Path=/;Domain=domainvalue;Max-Age=seconds;HTTPOnly");
PS:對於HTTPS,仍是能夠設置Secure字段,對Cookie進行安全加密。服務器
這是本質上不是預防XSS,而是在被攻破時候不容許JS讀取Cookie。cookie
2.處理富文本app
有些數據由於使用場景問題,並不能直接在服務端進行轉義存儲。不過富文本數據語義是完整的HTML代碼,在輸出時也不會拼湊到某個標籤的屬性中,因此能夠當特殊狀況特殊處理。處理的過程是在服務端配置富文本標籤和屬性的白名單,不容許出現其餘標籤或屬性(例如script、iframe、form等),即」XSS Filter「。而後在存儲以前進行過濾(過濾原理沒有去探明)。
Java有個開源項目Anti-Samy是很是好的XSS Filter:
Policy ploicy = Policy.getInstance(POLICY_FILE_LOCATION); AntiSamy as = new AntiSamy(); CleanResults cr = as.scan(dirtyInput, policy); MyUserDao.storeUserProfile(cr.getCleanHTML());
PS:固然也能夠在前端顯示前過濾,可是我以爲,讓前端人員少作東西好,而且服務端只須要轉一次。
客戶端能夠乾的事
1. 輸入檢查
輸入檢查的邏輯,必須放在服務器端代碼中實現(由於用JavaScript作輸入檢查,很容易被攻擊者繞過)。目前Web開發的廣泛作法,是同時在客戶端JavaScript中和服務器代碼中實現相同的輸入檢查。客戶端JavaScript的輸入檢查,能夠阻擋大部分誤操做的正經常使用戶,從而節約服務資源。
PS:簡單說,就是輸入檢查,服務端和客戶端都要作。
另外攻擊者可能輸入XSS的地方,例如:
1.頁面中全部的input框
2.window.location(href、hash等)
3.window.name
4.document.referrer
5.document.cookie
6.localstorage
7.XMLHttpRequest返回的數據
PS:固然不止這些
2. 輸出檢查
通常就是在變量輸出到HTML頁面時,使用編碼或轉義的方式來防護XSS攻擊。XSS的本質就是「HTML注入」,用戶的數據被當成了HTML代碼一部分來執行,從而混淆了本來的語義,產生了新的語義。
觸發XSS的地方
1.document.write
2.xxx.innerHTML=
3.xxx.outerHTML=
4.innerHTML.replace
5.document.attachEvent
6.window.attachEvent
7.document.location.replace
8.document.location.assign
PS:若是使用jquery,就是那些append、html、before、after等,其實就是拼接變量到HTML頁面時產生。大部分的MVC框架在模板(view層)會自動處理XSS問題,例如AngularJS。
用什麼編碼轉義
主要有HTMLEncode和JavaScriptEncode這兩個,客戶端和服務端都能作。可是讓後端去作,我感受是不大靠譜的,由於數據的使用場景可能有幾種,能夠在標籤、屬性、或腳本里(甚至其餘終端使用),單單以一種方式去encode是很極限的。
1.HTMLEncode,就是將字符轉換成HTMLEntities,通常會轉(&、<、>、"、'、/)這6個字符。
2.JavaScriptEncode,是使用」\「對特殊字符進行轉義。
PS:我在《HtmlEncode和JavaScriptEncode(預防XSS)》一文總結了比較完整的HTMLEncode和JavaScriptEncode兩個前端函數的寫法,以及一點示例。
哪些地方須要編轉義
1.在HTML標籤、屬性中輸出——用HTMLEncode
2.在script標籤中輸出——用JavaScriptEncode
3.在事件中輸出——用JavaScriptEncode
<a href="#" onclick="funcA('$var')">test</a>
4.在CSS中輸出
用相似JavaScriptEncode的方式。將除了字母、數字外的全部字符都編碼成十六進制形式」\uHH「。
5.在地址中輸出
通常若是變量是整個URL,則先檢查變量是否以「http」開頭(不是則幫忙添加http),保證不會出現僞協議類的XSS攻擊。而後再對變量進行URLEncode。
PS:URLEncode會將字符轉換成」%HH「形式。
總結
前端開發人員要注意在正確的地方使用正確的編碼方式,有時爲了防護XSS,在一個地方咱們須要聯合HTMLEncode、JavaScriptEncode進行編碼,甚至是疊加,並非固定一種方式編碼(又是具體狀況具體分析)。
通常存儲型XSS風險高於反射型XSS。反射型XSS通常要求攻擊者誘使用戶點擊一個包含XSS代碼的URL連接;而存儲型只須要用戶查看一個正常的URL連接,當用戶打開頁面時,XSS Payload就會被執行。這樣漏洞極其隱蔽,且埋伏在用戶的正常業務中,風險很高。(引自白帽子講Web安全原文)
本文爲原創文章,轉載請保留原出處,方便溯源,若有錯誤地方,謝謝指正。