XSS 和 CSRF 攻擊的一些非常規防禦方法
一說到安全,大家總會特別敏感,尤其是有相當部分的前端開發者並不了解安全相關的知識,頗有談虎色變的感覺。具體到前端安全這個話題呢,又有些說不清道不明,因為大部分的防禦方案,總少不了後端的參與,也有開發者慢慢覺得好像安全都應該由後端來關注了。
其實不然,起碼 XSS CSRF 這一類的安全問題前端是一定要了解它們的原理和防禦方法的。從防禦方法上來說,XSS 和 CSRF 的防禦在業界都有比較成熟的方案了。本文將記錄一些比較新的防禦方案,可能有一些比較老的書籍或者文章中不會提及這些方法。
XSS
XSS 全稱 Cross Site Scripting ,跨站腳本攻擊,因為 CSS 這名字老早就被樣式表拿走了,大家都在 web 這個領域,重名又不好看,所以只好起了個名字叫 XSS 了。說實話從 XSS 乾的事來講,其實並不太理解為什麼有個「跨站」在裡面,如果一定要強行解釋的話,大概是因為有可能會運行一個來自別人網站的腳本,把這個腳本叫「跨站」了吧。
好了,不重要。
重要的是它是誰,它從哪裡來,要到哪裡去……這樣的哲學問題有點難回答。我們換一個,重要的是它是什麼鬼,能幹什麼,怎麼防。
XSS 是什麼鬼
玩遊戲的人都知道在遊戲中經常出現一些奇葩的名字,比如「星辰並親了他一口」,看上去一臉不知道什麼鬼,但是當他有點事的時候,你就覺得好玩了,比如公會老大邀請他,就會有一條消息「公會老大邀請了星辰並親了他一口」,然後一公會的人哄堂大笑。
其實這種案例用專業的術語來說,就叫 XSS 了……
本來「公會老大邀請了XX」這樣一個句式,只希望XX是一個不會引起誤會的名字而已,結果因為有一個奇葩名字,直接改變了整句話的意思,引介出了意外的含義。
XSS 也是同樣的東西,比如我只想在頁面上顯示一個名字:
<span class="name">{{name}}</span>
但是,如果我的名字是長這樣的:
星辰<script>alert(SB)</script>
這時候就好玩了:
<span class="name">星辰<script>alert(SB)</script></span>
你看,頁面中憑空多了一段腳本。這個例子還算善良的,只是彈出來罵了你一句……
「難道他還能彈出來打我?」
呃……當然不是啦,但是人家可以偷偷幹壞事啊。你說說,你都用JS幹嘛?用戶登錄用的JS吧,讀取資料用的JS吧,點擊買東西、消費用的JS吧,查用戶有多少錢用的JS吧,基於 Cookies 也可以讀寫吧。好的,你用JS能幹的事情人家都能幹。
沒事偷你個登錄態,幫用戶消費兩塊錢,查下你用戶手機號是多少……接下來的事情我就不說了(無非就是前端程序員要背鍋離職唄?)
XSS 怎麼防禦
一個經典的防禦方法就是對內容進行轉義和過濾,比如
var escapeHtml = function(str) { if(!str) return ; str = str.replace(/&/g, &); str = str.replace(/</g, <); str = str.replace(/>/g, >); str = str.replace(/"/g, &quto;); str = str.replace(//g, '); // str = str.replace(/ /g,  ); return str;};var name = escapeHtml(`<script>alert(SB)</script>`);
此時 name 會變成
<script>alert('SB')</script>
這樣就會原樣顯示出來,再也無法耍流氓啦。
當然,富文本還要更麻煩一些,因為要保留一部分標籤和屬性,要不然全變純文本了,就不富了。這種情況一般通過黑名單進行過濾,或者白名單放行。即只允許一部分指定的標籤和屬性,其它的全部轉義掉。
CSP 大法
前面轉義的方法的出發點,是讓用戶的輸入不要變成程序,輸入的什麼就讓它輸出成什麼。
事實上現代瀏覽器為我們帶來了一個全新的安全策略,叫作內容安全策略,Content Security Policy,簡稱CSP。CSP的思路跟轉義不一樣,它的著手點是,如果一段代碼變成了程序,我們是否應該運行它。或者更準確一點說,它實際上是定義頁面上哪一些內容是可被信任的,哪一些內容是不被信任的。
因為我們自己的腳本是預先就知道並放在頁面上的,所以我們可以設置好信任關係,當有 XSS 腳本出現時,它並不在我們的信任列表中,因此可以阻止它運行。
它的具體使用方式是在 HTTP 頭中輸出 CSP 策略:
Content-Security-Policy: <policy-directive>; <policy-directive>
從語法上可以看到,一個頭可以輸出多個策略,每一個策略由一個指令和指令對應的值組成。指令可以理解為指定內容類型的,比如script-src
指令用於指定腳本,img-src
用於指定圖片。值則主要是來源,比如某個指定的URL,或者self
表示同源,或者unsafe-inline
表示在頁面上直接出現的腳本等。
詳細的指令和值,可以查看MDN相關頁面。
具體到上面的 XSS 例子,可以使用
Content-Security-Policy: script-src self;
這樣除了在同一個域名下的JS文件外,其它的腳本都不可以執行了,自然之前 XSS 的內容也就失效啦。簡單粗暴有沒有?
當然,如果你說,我就是要在頁面中放點內聯的腳本,不可以么?當然可以啦,CSP 設計的時候也考慮了這些情況,還是相當靈活的。你只需要指定一個 nonce 屬性,或者計算一下 hash 值,即可。詳細的用法看 MDN 哦。
說實話,用 CSP 來處理 XSS 攻擊還是不如轉義來得優雅,因為轉義可以不影響用戶輸入輸出,不改變內容的本質。但是 CSP 提供了足夠簡單而又靈活的方式來防禦 XSS ,可以很好地作為我們前端 XSS 防禦的最後一道防線。
CSRF
CSRF 也是個望文生不到義的詞,它的全稱是 Cross Site Request Foggy,即跨站請求攻擊。雖然也有跨站,但我覺得這個跨站還是相當可以理解的,它真的是從別的網站發起一個請求到我們的網站的。
當一個用戶登錄我們的網站後,在 Cookies 中會存放用戶的身份憑證。在大部分時候,就是一個 SessionId 。當用戶下次訪問我們的網站的時候,我們用這個憑證識別出用戶是誰,有沒有登錄態。
如果第三方網站的代碼請求了我們的網站,會發生什麼呢?比如
<img src="http://www.example.com/haha" />
雖然它是一張圖片,但它確實向www.example.com
發了一個請求,如此用戶有登錄態的話,其實就相當於是用戶自己發了一個請求。如果這個地址是一個發表文章、發布微博甚至轉賬之類的鏈接,那用戶就在不知情的情況下進行了一些操作。這也是比較嚴重的安全問題。
當然你可能會說,現在誰還這麼弱智,把這麼敏感的操作用 GET 啊?沒錯,你可以選擇用 POST ,但是這絲毫不能阻止 CSRF 攻擊的發生啊。
<iframe name="test"></iframe><form target="test" method="post" action="http://www.example.com/haha"> ...</form>
當這個表單提交的時候,我們就發了一個 POST 請求。華麗麗的 CSRF 。
CSRF 的常規防禦
CSRF 比較常規的防禦方式是通過判斷來源和加 token。
判斷來源比較簡單,主要是判斷referer
這個頭,如果不是自己的網站,就返回錯誤。
加 token 即同樣的隨機 token,在 cookies 中放一份,在表單中再放一份。這樣第三方網站就無法獲取到這個 token 是什麼。
但是這樣做也有一個比較明顯的問題,就是無法保證站內用戶的體驗。雖然你防了站外的攻擊,但是也降低了站內用戶的體驗。具體表現在如果同時打開多個表單,只有最後一個表單能成功提交。
same-site 的 Cookie
回想 CSRF 之所以能夠攻擊成功,核心原因就在於用戶的身份是放在 Cookies 中的,而不管你通過什麼方式訪問網站,都會帶上這個網站的 Cookies ,從第三方來的訪問自然也不能例外。
但是,Chrome 在這個問題上給了我們不同的答案,可以放第三方訪問時不帶 Cookies 。也就是說 Cookies 只有本站能用,來自第三方的訪問都不能使用。
具體的使用方式,是在打 Cookie 的時候,加上一個屬性:SameSite
,它的值有兩:
strict
任何來自第三方的請求都不能使用 Cookies ,包括通過鏈接點進來的lex
只有比較敏感的操作不帶 Cookies ,比如表單提交
針對 CSRF ,我們可以將 Cookies 設置成SameSite: strict
的,這樣就可以有效防禦 CSRF 了。不過比較可惜的是,目前只有 Chrome 才支持這一屬性。希望未來所有瀏覽器都能跟上腳步。
使用 SameSite 還會面臨一個問題,如果用戶是點擊鏈接進來的,那麼是不能使用登錄態的。一般可以考慮將用戶不敏感的信息不設置這個屬性,點進來仍然可以顯示當前用戶是誰,但是在請求的時候要求一個比較敏感的 SameSite 的 Cookies。這裡需要更多的實踐經驗來探索。
小結
本文重點講了 XSS 和 CSRF 這兩種比較常見的前端安全問題的防禦思路,尤其是如何使用一些新的規範、實現來幫助我們進行防禦。希望後面瀏覽器對這些安全相關防禦辦法的普及率能再高一些,讓前端工程師能花更少的時間寫出更安全的代碼。
作者: TooooBug
鏈接:http://www.imooc.com/article/details/id/18069
來源:慕課網
本文原創發佈於慕課網 ,轉載請註明出處,謝謝合作
推薦閱讀:
慕課網:【極力推薦】---安裝阿里代碼規約檢查插件
「乾貨」總結最新的官方穩定版nginxmongomysql快速安裝部署
雙重檢查鎖定與延遲初始化
【Kotlin中使用Dagger2】基礎入門篇(一)
日誌大了,怎麼辦?用我的日誌切割腳本吧!
推薦閱讀:
※如何看待黑客軍團第二季結局?
※美軍的網路和互聯網是不是物理隔離的?如果是的話,為什麼經常有新聞報道黑客入侵美軍網路?
※Anonymous對ISIS正式宣戰會對ISIS造成多大影響?
※中國有哪些類似 Hacker News 的網站?
※如何看待「神話——信息安全人才顛覆計劃」?