如何防禦跨站請求僞造 -CSRF- 攻擊?

CSRF 英文全稱是 Cross-site request forgery,所以又稱爲 “跨站請求僞造”,是指惡意誘導用戶打開被精心構造的網站,在該網站中,利用用戶的登錄狀態發起的跨站請求。簡單來講,CSRF 就是利用了用戶的登錄狀態,並通過被精心構造的網站利用用戶正常網站的會話狀態來做用戶不知情的事情。

用 GET 請求

特別典型的目前少見。一個變體我就遇到過:我不小心登錄了一個遊戲網站,遊戲網站不斷給我彈出圖片要我充錢。我點擊關閉,但是這個點擊動作觸發了一個操作

<img src=http://www. 手機話費.com/transfer?to= 惡意遊戲網站 &money=100>

扣了我的話費。這個沒有經過我的允許。我懂得維權,於是打電話給運營商:電信、移動或者聯通。找客服把話費要回來了。客服說這是我自己的操作,但是爲了提高用戶體驗,還是把話費退給我。客服這麼說到底是知道那個平臺是有問題的,影響了客戶權益,怕影響聲譽不肯承認;還是爲了解決問題不得而知,但運營商的這個接口是有問題。

我回憶了一下,當時是怎麼回事。模糊的記得,註冊時用的是手機號驗證碼自動註冊登錄。很可能是這時候登錄了運營商的網站,當時沒有太在意頁面是哪個網站的。這個遊戲網站用了運營商存儲在客戶端的 cookie 信息,向運營商發起僞造請求。這個問題很好解決,對於話費扣除這樣重要的接口,運營商不應該用 GET 請求,用 POST 並且要求一些信息數據。增加僞造成本。

SameSite 屬性

上面的場景,我並不確定當時的請求是 GET 請求,因爲畢竟在手機上也沒想到看源碼。如果運營商那邊還沒有那麼降智,遊戲那邊花了些力氣,模擬表單提交 POST 請求,怎麼來解決呢?

模擬請求的原理是截獲了客戶端的 cookie,Chrome 51 開始,瀏覽器的 Cookie 新增加了一個 SameSite 屬性,用來防止 CSRF 攻擊和用戶追蹤。它可以設置三個值。

Strict:完全禁止第三方 Cookie,跨站點時,任何情況下都不會發送 Cookie。這個規則過於嚴格,可能造成非常不好的用戶體驗。比如,當前網頁有一個 GitHub 鏈接,用戶點擊跳轉就不會帶有 GitHub 的 Cookie,跳轉過去總是未登陸狀態。

Lax:規則稍稍放寬,大多數情況也是不發送第三方 Cookie,但是導航到目標網址的 Get 請求除外。

None:網站可以選擇顯式關閉 SameSite 屬性,將其設爲 None。前提是必須同時設置 Secure 屬性(Cookie 只能通過 HTTPS 協議發送),否則無效。

Set-Cookie: widget_session=abc123; SameSite=None; Secure

SameSite 屬性防止攻擊的方法,提前是瀏覽器要支持。服務端還是需要對自己的接口負責。有下面幾種方式:

標誌請求來源

限制 HTTP 請求頭中的 Referer 字段,這個值將在瀏覽器頁面上發起請求時被主動添加,用於指定請求的來源頁面。作爲網站開發者,我們限制 Referer 請求頭,僅允許它來自我們已知的正常地址,而阻止惡意請求。

CSRF Token

服務端生成一個 token,瀏覽器接收到這個 Token 後存儲在本地存儲中,提交表單時,會將這個 token 再傳回服務端作比較,比較一致纔可以執行。

提交驗證碼

在表單中增加一個隨機的數字或字母驗證碼,通過強制用戶和應用進行交互,來有效地遏制 CSRF 攻擊。

在 HTTP 頭中自定義屬性並驗證

這種方法也是使用 token 並進行驗證,這裏並不是把 token 以參數的形式置於 HTTP 請求之中,而是把它放到 HTTP 頭中自定義的屬性裏。

同域安全策略

CORS,全稱 Cross-Origin Resource Sharing,是一種允許當前域(domain)的資源被其他域(domain)的腳本請求訪問的機制,通常由於同域安全策略(the same-origin security policy)瀏覽器會禁止這種跨域請求。

對於簡單請求,瀏覽器直接發出 CORS 請求。具體來說,就是在頭信息之中,增加一個 Origin 字段。Origin 字段用來說明,本次請求來自哪個源(協議 + 域名 + 端口)。服務器根據這個值,決定是否同意這次請求。不在許可範圍內:正常的 HTTP 迴應,響應頭不會添加 Access-Control-Allow-Origin。origin 在許可範圍內,響應頭會添加 Access-Control-xx。

Access-Control-Allow-Origin: http://brmayi.com
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: FooBar
Content-Type: text/html; charset=utf-8

非簡單請求是那種對服務器有特殊要求的請求,比如請求方法是 PUT 或 DELETE,或者 Content-Type 字段的類型是 application/json。

非簡單請求的 CORS 請求,會在正式通信之前,增加一次 HTTP 查詢請求,稱爲 "預檢" 請求(preflight)。瀏覽器先詢問服務器,當前網頁所在的域名是否在服務器的許可名單之中,以及可以使用哪些 HTTP 動詞和頭信息字段。只有得到肯定答覆,瀏覽器纔會發出正式的請求,否則就報錯。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/VUaNuXnLtMGAxEhbhPocBA