理解CSRF(跨站請求偽造)
原文出處Understanding CSRF
對于Express團隊的csrf模塊和csurf模塊的加密函數(shù)的用法我們經(jīng)常有一些在意韩玩。 這些在意是莫須有的,因為他們不了解CSRF token是如何工作的。 下面快速過一遍!
讀過后還有疑問?希望告訴我們錯誤?請開一個issue子房!
1. 一個CSRF攻擊是如何工作的?
在他們的釣魚站點就轧,攻擊者可以通過創(chuàng)建一個AJAX按鈕或者表單來針對你的網(wǎng)站創(chuàng)建一個請求:
<form action="https://my.site.com/me/something-destructive" method="POST"> <button type="submit">Click here for free money!</button></form>
這是很危險的证杭,因為攻擊者可以使用其他http方法例如 delete來獲取結(jié)果。 這在用戶的session中有很多關于你的網(wǎng)站的詳細信息時是相當危險的妒御。 如果一個不懂技術的用戶遇到了解愤,他們就有可能會輸入信用卡號或者個人安全信息。
2. 如果減輕CSRF攻擊乎莉?
只使用JSON api
使用JavaScript發(fā)起AJAX請求是限制跨域的送讲。 不能通過一個簡單的<form>來發(fā)送JSON奸笤, 所以,通過只接收JSON哼鬓,你可以降低發(fā)生上面那種情況的可能性监右。
禁用CORS
第一種減輕CSRF攻擊的方法是禁用cross-origin requests(跨域請求)。 如果你希望允許跨域請求异希,那么請只允許 OPTIONS, HEAD, GET 方法健盒,因為他們沒有副作用。
不幸的是称簿,這不會阻止上面的請求由于它沒有使用JavaScript(因此CORS不適用)扣癣。
檢驗referrer頭部
不幸的是,檢驗referrer頭部很麻煩憨降, 但是你可以阻止那些referrer頭部不是來自你的頁面的請求父虑。 這實在不值得麻煩。
舉個例子授药,你不能加載session如果這個請求的referrer頭部不是你的服務器士嚎。
GET總是冪等的
確保你的GET請求不會修改你數(shù)據(jù)庫中的相關數(shù)據(jù)。 這是一個初學者常犯的錯誤烁焙,使得你的應用不僅是易于遭受CSRF攻擊。
避免使用POST
因為<form>只能用GET或是POST, 而不能使用別的方法耕赘,例PUT, PATCH, DELETE骄蝇, 攻擊者很難有方法攻擊你的網(wǎng)站。
不要復寫方法
許多應用程序使用復寫方法來在一個常規(guī)表單中使用PUT, PATCH, 和DELETE請求操骡。 這會使得原先不易受攻擊的方法變得易受攻擊九火。
不要兼容舊瀏覽器
舊的瀏覽器不支持CORS或是其他安全政策。 通過不兼容舊瀏覽器 (那些不懂技術的人用的越多册招,我們越容易被攻擊), 你可以最小化受到攻擊的可能性岔激。
CSRF Tokens
最終的解決辦法是使用CSRF tokens。 CSRF tokens是如何工作的呢是掰?
- 服務器發(fā)送給客戶端一個token虑鼎。
- 客戶端提交的表單中帶著這個token。
- 如果這個token不合法键痛,那么服務器拒絕這個請求炫彩。
攻擊者需要通過某種手段獲取你站點的CSRF token, 他們只能使用JavaScript來做絮短。 所以江兢,如果你的站點不支持CORS, 那么他們就沒有辦法來獲取CSRF token丁频, 降低了威脅杉允。
確保CSRF token不能通過AJAX訪問到! 不要創(chuàng)建一個/CSRF
路由來獲取一個token邑贴, 尤其不要在這個路由上支持CORS!
token需要是不容易被猜到的, 讓它很難被攻擊者嘗試幾次得到叔磷。 它不需要是密碼安全的拢驾。 攻擊來自從一個未知的用戶的一次或者兩次的點擊, 而不是來自一臺服務器的暴力攻擊世澜。
3. BREACH攻擊
這也就是salt(加鹽)出現(xiàn)的原因独旷。 Breach攻擊相當簡單:如果服務器通過HTTPS+gzip多次發(fā)送相同或者相似的響應,攻擊者就可以猜測響應的內(nèi)容(使得HTTPS完全無用)寥裂。 解決辦法嵌洼?讓每一個響應都有那么一點不同。 于是封恰,CSRF tokens依據(jù)每一個不同的請求還有不同的時間來生成麻养。 但是服務器需要知道客戶端請求中帶的token是否是合法的。 因此:
- 一般認為安全加密的CSRF tokens是防護CSRF的關鍵
- CSRF tokens現(xiàn)在通常是一個秘鑰或者salt的hash
了解更多:
BREACH
CRIME
Defending against the BREACH Attack
注意诺舔,CSRF沒有_解決_BREACH攻擊鳖昌, 但是這個模塊通過隨機化請求來為你減輕BREACH攻擊。
4. salt不需要加密
因為客戶端知道salt!!! 服務器會發(fā)送 <salt>;<token>低飒,然后客戶端會通過請求返回相同的值給服務器许昨。服務器然后會檢驗 <secret>+<salt>=<token>。 salt必須跟token一起被發(fā)送給服務器褥赊,否則服務器不能驗證這個token糕档。 這是最簡單的加密方式。 還有很多方法拌喉,不過他們更加復雜速那,犯不著那么麻煩。
5. 創(chuàng)建tokens必須要快
因為每當進來一個請求他們就會被創(chuàng)建! 像Math.random().toString(36).slice(2)這么做也是性能足夠好的! 你不需要OpenSSL來為每一個請求創(chuàng)建一個密碼安全的token尿背。
6. 秘鑰不需要是加密的端仰,但需要是安全的
如果你正在使用一個數(shù)據(jù)庫后端來存儲session,客戶端是不會知道秘鑰的田藐,因為它被存儲在數(shù)據(jù)庫中荔烧。 如果你正在使用cookie來存儲session,那么秘鑰就會被存儲在cookie中發(fā)送給客戶端汽久。 因此茴晋, 確保cookie sessions 使用 httpOnly那樣客戶端就不能通過客戶端JavaScript來讀取到秘鑰!
7. 當你不正確的使用CSRF token
把它們加到JSON AJAX調(diào)用中
正如上面提到的,如果你不支持CORS并且你的API是傳輸?shù)膰栏竦腏SON回窘, 絕沒可能在你的AJAX 調(diào)用中加入CSRF token诺擅。
通過AJAX暴露你的CSRF token
不要創(chuàng)建一個GET /csrf
路由 并且尤其不要在這個路由上支持CORS。 不要發(fā)送CSRF token在API響應的body中啡直。
8. 結(jié)論
因為web正在向JSON API轉(zhuǎn)移烁涌,并且瀏覽器變得更安全苍碟,有更多的安全策略, CSRF正在變得不那么值得關注撮执。 阻止舊的瀏覽器訪問你的站點微峰,并盡可能的將你的API變成JSON API, 然后你將不再需要CSRF token抒钱。 但是為了安全起見蜓肆,你還是應該盡量允許他們尤其是當難以實現(xiàn)的時候。
https://github.com/pillarjs/understanding-csrf/blob/master/README_zh.md