理解CSRF(跨站請求僞造)

理解CSRF(跨站請求僞造)

原文出處Understanding CSRFhtml

對於Express團隊的csrf模塊和csurf模塊的加密函數的用法咱們常常有一些在乎。 這些在乎是莫須有的,由於他們不瞭解CSRF token是如何工做的。 下面快速過一遍!git

讀事後還有疑問?但願告訴咱們錯誤?請開一個issue!github

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

在他們的釣魚站點,攻擊者能夠經過建立一個AJAX按鈕或者表單來針對你的網站建立一個請求:web

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

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

若是減輕CSRF攻擊?

只使用JSON api

使用JavaScript發起AJAX請求是限制跨域的。 不能經過一個簡單的<form>來發送JSON, 因此,經過只接收JSON,你能夠下降發生上面那種狀況的可能性。數據庫

禁用CORS

第一種減輕CSRF攻擊的方法是禁用cross-origin requests(跨域請求)。 若是你但願容許跨域請求,那麼請只容許 OPTIONS, HEAD, GET 方法,由於他們沒有反作用。express

不幸的是,這不會阻止上面的請求因爲它沒有使用JavaScript(所以CORS不適用)。json

檢驗referrer頭部

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

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

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。 可是爲了安全起見,你仍是應該儘可能容許他們尤爲是當難以實現的時候。

相關文章
相關標籤/搜索