當我們說“前端安全問題”的時候,我們在說什麼
“安全”是個很大的話題,各種安全問題的型別也是種類繁多。如果我們把安全問題按照所發生的區域來進行分類的話,那麼所有發生在後端伺服器、應用、服務當中的安全問題就是“後端安全問題”,所有發生在瀏覽器、單頁面應用、Web頁面當中的安全問題則算是“前端安全問題”。比如說,SQL隱碼攻擊漏洞發生在後端應用中,是後端安全問題,跨站指令碼攻擊(XSS)則是前端安全問題,因為它發生在使用者的瀏覽器裡。
除了從安全問題發生的區域來分類之外,也可以從另一個維度來判斷:針對某個安全問題,團隊中的哪個角色最適合來修復它?是後端開發還是前端開發?
總的來說,當我們下面在談論“前端安全問題”的時候,我們說的是發生在瀏覽器、前端應用當中,或者通常由前端開發工程師來對其進行修復的安全問題。
8大前端安全問題
按照上面的分類辦法,我們總結出了8大典型的前端安全問題,它們分別是:
- 老生常談的XSS
- 警惕iframe帶來的風險
- 別被點選劫持了
- 錯誤的內容推斷
- 防火防盜防豬隊友:不安全的第三方依賴包
- 用了HTTPS也可能掉坑裡
- 本地儲存資料洩露
- 缺失靜態資源完整性校驗
由於篇幅所限,本篇文章先給各位介紹前4個前端安全問題。
老生常談的XSS
XSS是跨站指令碼攻擊(Cross-Site Scripting)的簡稱,它是個老油條了,在OWASP Web Application Top 10排行榜中長期霸榜,從未掉出過前三名。XSS這類安全問題發生的本質原因在於,瀏覽器錯誤的將攻擊者提供的使用者輸入資料當做JavaScript指令碼給執行了。
XSS有幾種不同的分類辦法,例如按照惡意輸入的指令碼是否在應用中儲存,XSS被劃分為“儲存型XSS”和“反射型XSS”,如果按照是否和伺服器有互動,又可以劃分為“Server Side XSS”和“DOM based XSS”。
無論怎麼分類,XSS漏洞始終是威脅使用者的一個安全隱患。攻擊者可以利用XSS漏洞來竊取包括使用者身份資訊在內的各種敏感資訊、修改Web頁面以欺騙使用者,甚至控制受害者瀏覽器,或者和其他漏洞結合起來形成蠕蟲攻擊,等等。總之,關於XSS漏洞的利用,只有想不到沒有做不到。
如何防禦
防禦XSS最佳的做法就是對資料進行嚴格的輸出編碼,使得攻擊者提供的資料不再被瀏覽器認為是指令碼而被誤執行。例如<script>
在進行HTML編碼後變成了<script>
,而這段資料就會被瀏覽器認為只是一段普通的字串,而不會被當做指令碼執行了。
編碼也不是件容易的事情,需要根據輸出資料所在的上下文來進行相應的編碼。例如剛才的例子,由於資料將被放置於HTML元素中,因此進行的是HTML編碼,而如果資料將被放置於URL中,則需要進行URL編碼,將其變為%3Cscript%3E。此外,還有JavaScript編碼、CSS編碼、HTML屬性編碼、JSON編碼等等。好在現如今的前端開發框架基本上都預設提供了前端輸出編碼,這大大減輕了前端開發小夥伴們的工作負擔。
其他的防禦措施,例如設定CSP HTTP Header、輸入驗證、開啟瀏覽器XSS防禦等等都是可選項,原因在於這些措施都存在被繞過的可能,並不能完全保證能防禦XSS攻擊。不過它們和輸出編碼卻可以共同協作實施縱深防禦策略。
你可以查閱OWASP XSS Prevention Cheat Sheet,裡面有關於XSS及其防禦措施的詳細說明。
警惕iframe帶來的風險
有些時候我們的前端頁面需要用到第三方提供的頁面元件,通常會以iframe的方式引入。典型的例子是使用iframe在頁面上新增第三方提供的廣告、天氣預報、社交分享外掛等等。
iframe在給我們的頁面帶來更多豐富的內容和能力的同時,也帶來了不少的安全隱患。因為iframe中的內容是由第三方來提供的,預設情況下他們不受我們的控制,他們可以在iframe中執行JavaScirpt指令碼、Flash外掛、彈出對話方塊等等,這可能會破壞前端使用者體驗。
如果說iframe只是有可能會給使用者體驗帶來影響,看似風險不大,那麼如果iframe中的域名因為過期而被惡意攻擊者搶注,或者第三方被黑客攻破,iframe中的內容被替換掉了,從而利用使用者瀏覽器中的安全漏洞下載安裝木馬、惡意勒索軟體等等,這問題可就大了。
如何防禦
還好在HTML5中,iframe有了一個叫做sandbox的安全屬性,通過它可以對iframe的行為進行各種限制,充分實現“最小許可權“原則。使用sandbox的最簡單的方式就是隻在iframe元素中新增上這個關鍵詞就好,就像下面這樣:
1 |
<iframe sandbox src="..."> ... </iframe> |
sandbox還忠實的實現了“Secure By Default”原則,也就是說,如果你只是新增上這個屬性而保持屬性值為空,那麼瀏覽器將會對iframe實施史上最嚴厲的調控限制,基本上來講就是除了允許顯示靜態資源以外,其他什麼都做不了。比如不準提交表單、不準彈窗、不準執行指令碼等等,連Origin都會被強制重新分配一個唯一的值,換句話講就是iframe中的頁面訪問它自己的伺服器都會被算作跨域請求。
另外,sandbox也提供了豐富的配置引數,我們可以進行較為細粒度的控制。一些典型的引數如下:
- allow-forms:允許iframe中提交form表單
- allow-popups:允許iframe中彈出新的視窗或者標籤頁(例如,window.open(),showModalDialog(),target=”_blank”等等)
- allow-scripts:允許iframe中執行JavaScript
- allow-same-origin:允許iframe中的網頁開啟同源策略
更多詳細的資料,可以參考iframe中關於sandbox的介紹。
別被點選劫持了
有個詞叫做防不勝防,我們在通過iframe使用別人提供的內容時,我們自己的頁面也可能正在被不法分子放到他們精心構造的iframe或者frame當中,進行點選劫持攻擊。
這是一種欺騙性比較強,同時也需要使用者高度參與才能完成的一種攻擊。通常的攻擊步驟是這樣的:
- 攻擊者精心構造一個誘導使用者點選的內容,比如Web頁面小遊戲
- 將我們的頁面放入到iframe當中
- 利用z-index等CSS樣式將這個iframe疊加到小遊戲的垂直方向的正上方
- 把iframe設定為100%透明度
- 受害者訪問到這個頁面後,肉眼看到的是一個小遊戲,如果受到誘導進行了點選的話,實際上點選到的卻是iframe中的我們的頁面
點選劫持的危害在於,攻擊利用了受害者的使用者身份,在其不知情的情況下進行一些操作。如果只是迫使使用者關注某個微博賬號的話,看上去彷彿還可以承受,但是如果是刪除某個重要檔案記錄,或者竊取敏感資訊,那麼造成的危害可就難以承受了。
如何防禦
有多種防禦措施都可以防止頁面遭到點選劫持攻擊,例如Frame Breaking方案。一個推薦的防禦方案是,使用X-Frame-Options:DENY這個HTTP Header來明確的告知瀏覽器,不要把當前HTTP響應中的內容在HTML Frame中顯示出來。
關於點選劫持更多的細節,可以查閱OWASP Clickjacking Defense Cheat Sheet。
錯誤的內容推斷
想象這樣一個攻擊場景:某網站允許使用者在評論裡上傳圖片,攻擊者在上傳圖片的時候,看似提交的是個圖片檔案,實則是個含有JavaScript的指令碼檔案。該檔案逃過了檔案型別校驗(這涉及到了惡意檔案上傳這個常見安全問題,但是由於和前端相關度不高因此暫不詳細介紹),在伺服器裡儲存了下來。接下來,受害者在訪問這段評論的時候,瀏覽器會去請求這個偽裝成圖片的JavaScript指令碼,而此時如果瀏覽器錯誤的推斷了這個響應的內容型別(MIME types),那麼就會把這個圖片檔案當做JavaScript指令碼執行,於是攻擊也就成功了。
問題的關鍵就在於,後端伺服器在返回的響應中設定的Content-Type Header僅僅只是給瀏覽器提供當前響應內容型別的建議,而瀏覽器有可能會自作主張的根據響應中的實際內容去推斷內容的型別。
在上面的例子中,後端通過Content-Type Header建議瀏覽器按照圖片來渲染這次的HTTP響應,但是瀏覽器發現響應中其實是JavaScript,於是就擅自做主把這段響應當做JS指令碼來解釋執行,安全問題也就產生了。
如何防禦
瀏覽器根據響應內容來推斷其型別,本來這是個很“智慧”的功能,是瀏覽器強大的容錯能力的體現,但是卻會帶來安全風險。要避免出現這樣的安全問題,辦法就是通過設定X-Content-Type-Options這個HTTP Header明確禁止瀏覽器去推斷響應型別。
同樣是上面的攻擊場景,後端伺服器返回的Content-Type建議瀏覽器按照圖片進行內容渲染,瀏覽器發現有X-Content-Type-OptionsHTTP Header的存在,並且其引數值是nosniff,因此不會再去推斷內容型別,而是強制按照圖片進行渲染,那麼因為實際上這是一段JS指令碼而非真實的圖片,因此這段指令碼就會被瀏覽器當作是一個已經損壞或者格式不正確的圖片來處理,而不是當作JS指令碼來處理,從而最終防止了安全問題的發生。
更多關於X-Content-Type-Options的細節請參考這裡。
小結
本文對前端安全問題進行了一次梳理,介紹了其中4個典型的前端安全問題,包括它們發生的原因以及防禦辦法。在下篇文章中,我們將介紹其他的幾個前端安全問題,敬請期待。
文/ThoughtWorks馬偉