繁體中文(香港)
  • csrf attack
  • web security
  • cross-site request forgery
  • cookie security
  • same-origin policy
  • csrf prevention
  • SameSite

深入理解 CSRF

提供對跨網站請求偽造(CSRF)攻擊的深入探討,解釋其機制,示範示例,並詳述各種預防方法以增強網絡應用程式的安全性。

Yijun
Yijun
Developer

當進行網頁開發時,尤其涉及 Cookie,我們經常會聽到類似 "這個設定有助於防止 CSRF" 的說法。然而,很多人對於 "CSRF" 的真正含義只有模糊的概念。

今天,我們將深入探討 CSRF(跨網站請求偽造),這是一個常見的網絡安全漏洞。這將有助於我們更有效地處理 CSRF 相關問題。

什麼是 CSRF?

CSRF(跨網站請求偽造)是一種網絡攻擊,攻擊者誘使已經認證的用戶執行非預期操作。簡單來說,就是 "黑客假裝成用戶以執行未經授權的操作"。

CSRF 如何運作

要瞭解 CSRF,我們需要掌握幾個關鍵概念:

瀏覽器的同源政策

同源政策是瀏覽器中的一項安全功能,限制來自一個來源的文件或腳本如何與另一個來源的資源互動。

一個來源由協議(如 HTTP 或 HTTPS)、域名和端口號組成。例如,https://example.com:443 是一個來源,而 https://demo.com:80 是另一個。

同源政策限制不同來源頁面之間的數據訪問,這意味著:

  • 一個來源的 JavaScript 無法讀取另一個來源的 DOM
  • 一個來源的 JavaScript 無法讀取另一個來源的 Cookie、IndexedDB 或 localStorage
  • 一個來源的 JavaScript 無法向另一個來源發送 AJAX 請求(除非使用 CORS)

然而,為了保持 Web 的開放性和互操作性(如從 CDNs 加載資源或向第三方 APIs 發送請求進行日誌記錄),同源政策不限制跨來源的網絡請求:

  • 頁面可以向任何來源發送 GET 或 POST 請求(如加載圖片或提交表單)
  • 可以包含來自任何來源的資源(如 <script><img><link><iframe> 標籤)

自動 Cookie 發送機制是瀏覽器的一項重要功能。當瀏覽器向一個域發送請求時,它會自動附上該域的所有 Cookie。這個過程是自動的,不需要任何 JavaScript 代碼或用戶交互。

這一機制可以讓網站輕鬆地記住用戶的登入狀態,因為每個請求自動攜帶用戶身份信息。 加粗 例如,當你登入一個銀行網站(bank.com)並獲取身份 Cookie,然後當你點擊查看你的對帳單時,瀏覽器會自動找到所有匹配 bank.com 的 Cookie 並將它們附加到對帳單請求。銀行的伺服器隨後可以從後台識別你並返回你的對帳單信息。

CSRF 攻擊步驟

  1. 用戶登入目標網站(如銀行網站),獲得身份驗證 Cookie。 這一步使用自動 Cookie 發送機制。當銀行網站設置身份驗證 Cookie 後,瀏覽器將自動將此 Cookie 附加到發送給該網站的每個請求中。

  2. 在不登出的情況下,用戶訪問了惡意網站。 此時,由於同源政策,惡意網站無法直接讀取或修改銀行網站的 Cookie。這保護了用戶的身份信息不被直接竊取。

  3. 惡意網站包含了一個發向目標網站的請求(如轉賬操作)。 雖然同源政策限制跨來源訪問,但它允許跨來源網絡請求,如通過 <img><form> 標籤發起的請求。攻擊者利用了這個 "漏洞"。

  4. 用戶的瀏覽器自動發送這一請求,並附上目標網站的 Cookie。 這是 CSRF 攻擊的核心。它利用了同源政策允許跨來源請求和自動 Cookie 發送機制(即使由惡意網站觸發的請求也會攜帶匹配域的 Cookie)。

  5. 目標網站接收到請求,驗證 Cookie 有效後執行操作。 伺服器無法判斷請求是否來自合法用戶操作,因為附加的 Cookie 是有效的。

CSRF 攻擊示例

讓我們用一個具體的例子來說明 CSRF 攻擊是如何發生的。我們將使用一個虛構的銀行網站 bank.com 作為示例。

首先,用戶訪問 https://bank.com 並登入他們的帳戶。

成功登入後,伺服器設置了一個身份驗證 Cookie,例如:

用戶在銀行網站上進行轉賬操作,比如轉賬 1000 美元給 Alice。這一操作可能發送如下請求:

現在,假設攻擊者創建了一個包含以下 HTML 的惡意網站 https://evil.com

當用戶在未登出銀行帳戶的情況下點擊 https://evil.com 的鏈接,因為他們已經登入 bank.com,瀏覽器擁有一個有效的 session_id Cookie。

惡意頁面加載後,會自動提交隱藏的表單,向 https://bank.com/transfer 發送轉賬請求。

用戶的瀏覽器自動將 bank.com Cookie 附加到此請求。bank.com 伺服器接收到請求,驗證 Cookie 有效後執行了這一未經授權的轉賬操作。

常見的 CSRF 攻擊防範方法

以下是幾種常用的 CSRF 防禦方法。我們將詳細解釋每一種方法的原理及其如何有效防止 CSRF 攻擊:

使用 CSRF 令牌

CSRF 令牌是抵御 CSRF 攻擊最常見且有效的方法之一。其工作原理如下:

  1. 伺服器為每個會話生成唯一且不可預測的令牌。
  2. 此令牌嵌入到所有敏感操作的表單中。
  3. 當用戶提交表單時,伺服器驗證令牌的有效性。

因為 CSRF 令牌是一個綁定到用戶會話的唯一值,攻擊者無法知道或猜測這個值(因為每個會話不同),即使攻擊者誘使用戶發送請求,伺服器也會因為缺少有效的 CSRF 令牌而拒絕該請求。

實施例子:

在伺服器端(使用 Node.js 和 Express):

在前端 JavaScript:

檢查 Referer 標頭

Referer 標頭包含發起請求的頁面的 URL。通過檢查 Referer 標頭,伺服器可以確定請求是否來自合法來源。

由於 CSRF 攻擊通常來自不同的域名,Referer 標頭將顯示攻擊者的域名。通過驗證 Referer 是否為預期值,可以封鎖來自未知來源的請求。

然而,值得注意的是,這種方法並不完全可靠,因為某些瀏覽器可能不會發送 Referer 標頭,用戶也可以通過瀏覽器設置或插件禁用 Referer 標頭。

實施例子:

SameSite 是用於控制 Cookie 是否與跨站點請求一起發送的 Cookie 屬性。它有三個可能的值:

  • Strict: Cookie 僅在同一站點的請求中發送。
  • Lax: Cookie 在同一站點的請求和頂級導航中發送。
  • None: Cookie 在所有跨站點請求中發送(必須與 Secure 屬性一起使用)。

SameSite 設置為 Strict 時,可以完全防止第三方網站發送 Cookie,從而有效防範 CSRF 攻擊。 如果 SameSite 設置為 Lax,則在允許一些常見的跨站使用情況(如從外部鏈接進入網站)的同時,保護敏感操作。

實施例子:

使用自定義請求標頭

對於 AJAX 請求,可以添加自定義請求標頭。由於同源政策的限制,攻擊者無法在跨站請求中設置自定義標頭。伺服器可以檢查這一自定義標頭的存在性來驗證請求的合法性。

實施例子:

在前端:

在伺服器端:

雙重 Cookie 驗證是有效的 CSRF 防禦技術。其核心原理是伺服器生成一個隨機令牌,將其設置為 Cookie 並將其嵌入頁面(通常是作為隱藏表單字段)。當瀏覽器發送請求時,它自動包含該 Cookie,而頁面的 JavaScript 將該令牌作為請求參數發送。然後伺服器驗證 Cookie 中的令牌與請求參數中的令牌是否匹配。

雖然攻擊者可以在跨站請求中包含目標網站的 Cookie,但他們無法讀取或修改 Cookie 的值,也無法訪問或修改頁面中的令牌值。要求請求同時包含來自 Cookie 和參數的令牌,確保請求來自有權限讀取 Cookie 的來源,從而有效防禦 CSRF 攻擊。

對敏感操作使用重新驗證

對於特別敏感的操作(如更改密碼或進行大額轉賬),可以要求用戶重新驗證。 這為用戶提供了一個額外的安全檢查點。即使用戶成功發起了 CSRF 攻擊,也無法通過重新驗證步驟。

實施建議:

  • 在執行敏感操作之前,重定向到單獨的身份驗證頁面。
  • 在此頁面上,要求用戶輸入密碼或其他身份驗證信息。
  • 驗證通過後,生成一次性令牌並在後續敏感操作中使用該令牌。

總結

通過這次深入討論,我們希望你現在對 CSRF 攻擊有了更全面的理解。 我們不僅了解了 CSRF 如何運作,還探討了各種有效的防禦措施。所有這些方法都可以有效增強網絡應用程式的安全性。

希望這些知識可以幫助你在日常開發中更好地處理 CSRF 相關問題,並建立更安全的網絡應用程式。