理解CSRF(跨站請求偽造)


理解CSRF(跨站請求偽造)

原文出處Understanding CSRF

對於Express團隊的csrf模塊和csurf模塊的加密函數的用法我們經常有一些在意。 這些在意是莫須有的,因為他們不了解CSRF token是如何工作的。 下面快速過一遍!

讀過后還有疑問?希望告訴我們錯誤?請開一個issue!

一個CSRF攻擊是如何工作的?

在他們的釣魚站點,攻擊者可以通過創建一個AJAX按鈕或者表單來針對你的網站創建一個請求:

<form action="https://my.site.com/me/something-destructive" method="POST">
  <button type="submit">Click here for free money!</button>
</form>

這是很危險的,因為攻擊者可以使用其他http方法例如 delete 來獲取結果。 這在用戶的session中有很多關於你的網站的詳細信息時是相當危險的。 如果一個不懂技術的用戶遇到了,他們就有可能會輸入信用卡號或者個人安全信息。

如果減輕CSRF攻擊?

只使用JSON api

使用JavaScript發起AJAX請求是限制跨域的。 不能通過一個簡單的<form>來發送JSON, 所以,通過只接收JSON,你可以降低發生上面那種情況的可能性。

禁用CORS

第一種減輕CSRF攻擊的方法是禁用cross-origin requests(跨域請求)。 如果你希望允許跨域請求,那么請只允許 OPTIONS, HEAD, GET 方法,因為他們沒有副作用。

不幸的是,這不會阻止上面的請求由於它沒有使用JavaScript(因此CORS不適用)。

檢驗referrer頭部

不幸的是,檢驗referrer頭部很麻煩, 但是你可以阻止那些referrer頭部不是來自你的頁面的請求。 這實在不值得麻煩。

舉個例子,你不能加載session如果這個請求的referrer頭部不是你的服務器。

GET總是冪等的

確保你的GET請求不會修改你數據庫中的相關數據。 這是一個初學者常犯的錯誤,使得你的應用不僅是易於遭受CSRF攻擊。

避免使用POST

因為<form>只能用GET或是POST, 而不能使用別的方法,例如PUT, PATCH, DELETE, 攻擊者很難有方法攻擊你的網站。

不要復寫方法

許多應用程序使用復寫方法來在一個常規表單中使用PUT, PATCH, 和DELETE請求。 這會使得原先不易受攻擊的方法變得易受攻擊。

不要兼容舊瀏覽器

舊的瀏覽器不支持CORS或是其他安全政策。 通過不兼容舊瀏覽器 (那些不懂技術的人用的越多,我們越容易被攻擊), 你可以最小化受到攻擊的可能性。

CSRF Tokens

最終的解決辦法是使用CSRF tokens。 CSRF tokens是如何工作的呢?

  1. 服務器發送給客戶端一個token。
  2. 客戶端提交的表單中帶着這個token。
  3. 如果這個token不合法,那么服務器拒絕這個請求。

攻擊者需要通過某種手段獲取你站點的CSRF token, 他們只能使用JavaScript來做。 所以,如果你的站點不支持CORS, 那么他們就沒有辦法來獲取CSRF token, 降低了威脅。

確保CSRF token不能通過AJAX訪問到! 不要創建一個/CSRF路由來獲取一個token, 尤其不要在這個路由上支持CORS!

token需要是不容易被猜到的, 讓它很難被攻擊者嘗試幾次得到。 它不需要是密碼安全的。 攻擊來自從一個未知的用戶的一次或者兩次的點擊, 而不是來自一台服務器的暴力攻擊。

BREACH攻擊

這也就是salt(加鹽)出現的原因。 Breach攻擊相當簡單:如果服務器通過HTTPS+gzip多次發送相同或者相似的響應,攻擊者就可以猜測響應的內容(使得HTTPS完全無用)。 解決辦法?讓每一個響應都有那么一點不同。 於是,CSRF tokens依據每一個不同的請求還有不同的時間來生成。 但是服務器需要知道客戶端請求中帶的token是否是合法的。 因此:

  1. 一般認為安全加密的CSRF tokens是防護CSRF的關鍵
  2. CSRF tokens現在通常是一個秘鑰或者salt的hash

了解更多:

注意,CSRF沒有_解決_BREACH攻擊, 但是這個模塊通過隨機化請求來為你減輕BREACH攻擊。

salt不需要加密

因為客戶端知道salt!!! 服務器會發送 <salt>;<token> ,然后客戶端會通過請求返回相同的值給服務器。服務器然后會檢驗 <secret>+<salt>=<token> 。 salt必須跟token一起被發送給服務器,否則服務器不能驗證這個token。 這是最簡單的加密方式。 還有很多方法,不過他們更加復雜,犯不着那么麻煩。

創建tokens必須要快

因為每當進來一個請求他們就會被創建!Math.random().toString(36).slice(2)這么做也是性能足夠好的! 你不需要OpenSSL來為每一個請求創建一個密碼安全的token。

秘鑰不需要是加密的,但需要是安全的

如果你正在使用一個數據庫后端來存儲session,客戶端是不會知道秘鑰的,因為它被存儲在數據庫中。 如果你正在使用cookie來存儲session,那么秘鑰就會被存儲在cookie中發送給客戶端。 因此, 確保cookie sessions 使用 httpOnly 那樣客戶端就不能通過客戶端JavaScript來讀取到秘鑰!

當你不正確的使用CSRF token

把它們加到JSON AJAX調用中

正如上面提到的,如果你不支持CORS並且你的API是傳輸的嚴格的JSON, 絕沒可能在你的AJAX 調用中加入CSRF token。

通過AJAX暴露你的CSRF token

不要創建一個GET /csrf路由 並且尤其不要在這個路由上支持CORS。 不要發送CSRF token在API響應的body中。

結論

因為web正在向JSON API轉移,並且瀏覽器變得更安全,有更多的安全策略, CSRF正在變得不那么值得關注。 阻止舊的瀏覽器訪問你的站點,並盡可能的將你的API變成JSON API, 然后你將不再需要CSRF token。 但是為了安全起見,你還是應該盡量允許他們尤其是當難以實現的時候。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM