標籤:
閱讀目錄
XSS(Cross Site Scripting),又稱跨站指令碼,XSS的重點不在於跨網站,而是在於指令碼的執行。在WEB前端應用日益發展的今天,XSS漏洞尤其容易被開發人員忽視,最終可能造成對個人資訊的泄漏。如今,仍然沒有統一的方式來檢測XSS漏洞,但是對於前端開發人員而言,仍是可以在某些細微處避免的,因此本文會結合筆者的學習和經驗總結解決和避免的一些方案,並簡要從webkit核心分析瀏覽器核心對於XSS避免所做的努力,瞭解底層基礎設施對預防XSS所做的貢獻。
XSS的種類和特點
此處不詳細講解XSS的一些細節
XSS的目標是讓其他網站的js檔案運行在目標網站的上,這主要發生在頁面渲染階段。在該階段發生了某些非預期的指令碼行為,該指令碼可能來自使用者的輸入,也可能來自域外的其他js檔案,不一而足。XSS的發生起源來自於使用者輸入,因此XSS根據使用者輸入資料以何種形式、何時觸發XSS、是否有後端伺服器的參與劃分為三種類型,分別是反射型XSS、持久型XSS和DOM XSS。
反射型XSS
反射型XSS,顧名思義在於“反射”這個一來一回的過程。反射型XSS的觸發有後端的參與,而之所以觸發XSS是因為後端解析使用者在前端輸入的帶有XSS性質的指令碼或者指令碼的data URI編碼,後端解析使用者輸入處理後返回給前端,由瀏覽器解析這段XSS指令碼,觸發XSS漏洞。因此如果要避免反射性XSS,則必須需要後端的協調,在後端解析前端的資料時首先做相關的字串檢測和轉義處理;同時前端同樣也許針對使用者的資料做excape轉義,保證資料來源的可靠性。
e.x.
localhost/test.php
<?php echo $_GET[‘name‘] ?>
如果通過 localhost/test.php?name=alert(document.cookie) 訪問頁面,那麼經過後端伺服器的處理,就會造成反射性XSS的發生。
同理,通過傳入data uri編碼的字串也會導致XSS,如 localhost/test.php?name=data:text/html;charset=utf-8;base64,PHNjcmlwdD5hbGVydChkb2N1bWVudC5jb29raWUpPC9zY3JpcHQ+ 會導致同樣的問題。該段編碼的字串解碼後是“alert(document.cookie)”。
持久型XSS
持久型XSS仍然需要服務端的參與,它與反射型XSS的區別在於XSS代碼是否持久化(硬碟,資料庫)。反射型XSS過程中後端伺服器僅僅將XSS代碼儲存在記憶體中,並為持久化,因此每次觸發反射性XSS都需要由使用者輸入相關的XSS代碼;而持久型XSS則僅僅首次輸入相關的XSS代碼,儲存在資料庫中,當下次從資料庫中擷取該資料時在前端未加字串檢測和excape轉碼時,會造成XSS,而且由於該漏洞的隱蔽性和持久型的特點,在多人開發的大型應用和跨應用間的資料擷取時造成的大範圍的XSS漏洞,危害尤其大。這就需要開發人員培養良好的WEB前端安全意識,不僅僅不能相信使用者的輸入,也不能完全相信儲存在資料庫中的資料(即後端開發人員忽視的資料安全檢測)。針對持久型XSS沒有好的解決方式,只能由開發人員保證。當然規則是由開發人員制定,如果忽略使用者體驗的話,可以制定一套嚴謹的輸入規則,對相關關鍵詞和輸入類型(如data URI檢測,禁止輸入)的檢測和禁止,儘可能規避使用者發現XSS漏洞的可能性,從源頭處理。
DOM XSS
DOM XSS完全在前端瀏覽器觸發,無需服務端的參與,因此這是前端開發工程師的“地盤”,理應獲得我們的關注。
e.x.
localhost/test.html
<script>eval(‘alert(location.hash.slice("1"))‘);</script>
如果訪問localhost/test.html#document.cookie ,那麼就會觸發最簡單的危害非常大的DOM XSS。它完全沒有服務端的參與,僅僅由使用者的輸入和不安全的指令碼執行造成,當然在本例中僅僅是最簡單的情況,如果使用者輸入字串‘’或者text/html格式的data URI,則更難檢測,也危害更大,駭客操作起來更為容易。
因此預防DOM XSS,需要前端開發人員警惕使用者所有的輸入資料,做到資料的excape轉義,同時儘可能少的直接輸出HTML的內容;不用eval、new Function、setTimeout等較為hack的方式解析外站資料和執行js指令碼;禁止內聯事件處理函數;如果在考慮安全性的前提下需要擷取外站指令碼的執行結果,可以採用前端沙箱(建立空的iframe執行指令碼,該iframe無法操作當前文件物件模型)、worker線程的方式完成,保證DOM的安全。
XSS預防
XSS漏洞難以檢測,但是為了WEB安全仍需要儘力避免,在本節將會針對三種類型XSS漏洞提出對應解決方案,並從其他角度提供更具啟發性的意見。
針對反射型XSS,在對應的小節中也提到過,需要服務端和前端共同預防,針對使用者輸入的資料做解析和轉義,對於前端開發而言,則是善於使用escape,針對data URI內容做正則判斷,禁止使用者輸入非顯示資訊,如MIME類型為“text/html,text/plain”類型的內容。
對於儲存型XSS,處理方式仍然類同於反射性XSS。
對於DOM XSS,則需要慎之又慎。由於造成XSS的原因在於使用者的輸入,因此在前端,需要特別注意以下的使用者輸入源:
“
document.URL,
location.hash,
location.research,
document.referrer(此處應尤為注意,referrer屬性雖然可用於避免CSRF,但可觸發XSS攻擊),
XHR傳回值(跨域傳回值),
form表單及各種input框
“
針對以上輸入源,需要做相對於的檢測和轉義。在以上輸入源中擷取資料後,可能會有各種DOM操作或純粹的js計算,這些操作則是真正觸發XSS的罪魁禍首:
“
1,直接輸出HTML內容
document.body.innerHTML = ...
document.body.outterHTML = ...
document.write()
2,HTML標籤內聯指令碼
<img src=‘abc‘ onerror=alert(‘error‘)>
3,直接執行指令碼
eval
new Function(){}
setTimeout()
window.execScript()
4,開啟新頁面觸發XSS(包括反射型XSS和持久型XSS)
window.open()
location.href = ...
location.hash = ...
”
在操作DOM時,需要尤其注意上述操作,針對可能造成的XSS需要進行字串轉義。當然,有些操作是完全可以避免的:對於innerHTML的拼接操作,需要摒棄jQuery式的鏈式操作而使用前端模版如artTemplate,也可選擇使用由後端渲染好的可靠的資料,這樣既保證效能也確保安全;對於HTML標籤內嵌js,則需要完全避免,這是一種容錯率很低的實現;直接執行指令碼和解析資料,則需避免eval和new Funciton等操作,改為JSON.parse、iframe沙箱和webWorker執行;而針對開啟新頁面觸發的XSS則需要開發人員自行把控。
另外的嘗試
上文提到的僅僅是對應的XSS避免方案,但是如果將目光放置在全域,站在瀏覽器的角度上,則會變的更為柳暗花明。現階段,大多數瀏覽器都支援多種安全性原則,如沙箱機制,跨域機制,跨文檔訊息和CSP。在這裡,我們關注CSP(Content Security Policy),又稱Alibaba Content Security Service協議,CSP通過服務端響應的HTTP頭部來制定網頁相關資源的載入域,這些資源限定於js檔案、css檔案、image、iframe、字型和其他對象(如object、applet)。
CSP通過HTTP頭部由服務端制定,頭部類型由於曆史原因總共由三種,這三種僅僅是相容性的差別,針對chrome瀏覽器,我們僅需關注Content-Security-Policy頭部。CSP頭部的定義規則如下:
Content-Security-Policy: 名 值; 名 值; 名 值;
具體的指令名如:
指令值的規範如:
因此,如果我們要避免XSS攻擊,可以限定指令碼的來源域,如:
Content-Security-Policy: default-src ‘self‘ ajax.googleapis.com;
這樣,非本域和ajax.googleapis.com域下的其他指令碼不會被載入,避免了XSS。
在這裡需要強調一點的是,預設CSP會禁止script代碼塊的執行;禁止內聯事件處理函數;禁止內聯樣式;禁止eval和new Function。對於內聯script代碼塊和內聯樣式,可通過CSP的header設定,如Content-Security-Policy: default-src ‘self‘; script-src ‘unsafe-inline‘;。
CSP有一個指令需要注意,即report-uri,它會將錯誤資訊主動發送至改cgi(sevlet),用於管理員的統一管控。report-uri屬性將會在下文中涉及到。
webkit中的XSS組件
XSS攻擊主要發生在頁面的渲染時,當瀏覽器的渲染引擎擷取到該頁面並開始解析時,是可以在該階段進行安全校正的,具體的時間節點則是在詞法分析後針對每個token做過濾。
在webkit中,由HTMLDocumentParser解析得到token後,使用XSSAuditor進行過濾,具體則是在filterToken中執行,不僅僅是針對token的名稱,其屬性也是監測重點。在webkit中採用黑名單機制,針對“,,,”做重點排查,當發現相關隱患時,產生相關資訊XSSInfo,由XSSAuditorDelegate類發送給對應的cgi,該cgi的地址正是CSP中的指令值report-uri,當然也可以手動制定該值。
預設,XSSAuditor是啟用的,但是XSSAuditor在發現XSS行為時卻有多種,這些行為可以配置,這就涉及到HTTP頭部X-XSS-Protection。該頭部並不是W3C和IETF的規範,而是非標準實現,通過對該頭部的賦值來定製XSSAuditor的相關行為。
預設情況,XSSAuditor處於重寫入模式(js代碼處在非執行狀態),即X-XSS-Protection:1;如果要禁用XSSAuditor,可以X-XSS-Protection:0;當設定為X-XSS-Protection:1;mode=block,則會在XSSAuditor作用時禁止網頁顯示,呈現給使用者的則是空白頁;若設定為X-XSS-Protection:1;report=... ,則會將相關統計資訊發送給CSP中定義的report-uri。XSSAuditor無法完全避免XSS,但畢竟在瀏覽器層面提供了一層檢查機制,從HTML tag上保證其可靠性。
總結
XSS漏洞難以發現,但是作為開發人員需要於細節處避免製造XSS漏洞,而對於CSP規範和webkit的XSSAuditor機制的使用,我們不應抱著依靠它們的想法來解決XSS,畢竟不是所有的頁面都可以容忍CSP的嚴格,XSSAuditor機制也僅僅針對chrome而言,並且存在多種bypass繞過檢查,如通過各種HTML實體編碼、url編碼和js編碼。因此,我們仍需以人為本,規範開發習慣,提高WEB前端安全意識。
參考文章:
1 瀏覽器安全性原則說之Alibaba Content Security Service策略CSP
2 UNDERSTANDING XSS AUDITOR
3 webkit技術內幕
http://www.cnblogs.com/accordion/p/5446174.html
XSS分析及預防(轉)