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

深入了解 CSRF

深入探討跨站請求偽造 (CSRF) 攻擊,說明其運作機制、示範範例,並詳述各種預防方法以提高網頁應用程式的安全性。

Yijun
Yijun
Developer

在從事網頁開發時,尤其是使用 cookies 時,經常會聽到類似「這設定有助於防止 CSRF」這樣的說法。然而,許多人對於「CSRF」這個名詞的真正涵意只有模糊的概念。

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

什麼是 CSRF?

CSRF (Cross-Site Request Forgery) 是一種網頁攻擊,攻擊者會誘騙已驗證的使用者執行未預期的操作。簡單來說,這就是「駭客偽裝成使用者來執行未授權操作」。

CSRF 是如何運作的

要了解 CSRF,我們需要掌握一些關鍵概念:

瀏覽器的同源政策

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

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

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

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

但是,為了保持 Web 的開放性和互操作性(如從 CDN 加載資源或為日誌發送第三方 API 請求),同源政策不會限制跨來源網絡請求:

  • 頁面可以向任意來源發送 GET 或 POST 請求(如加載圖像或提交表單)
  • 任意來源的資源都可以被包括在內(如 <script><img><link><iframe> 標籤)

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

這一機制使網站能夠輕鬆記住用戶的登入狀態,因為每個請求中都自動攜帶用戶的身份信息。 Bold 例如,當你登入銀行網站 (bank.com) 並獲取身份 cookie,然後當你點擊查看對賬單時,瀏覽器會自動發現所有匹配 bank.com 的 cookies 並將其附加到對賬單請求中。銀行伺服器因此能夠從後端識別你並返回你的對賬單信息。

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。這個操作可能發送出如下請求:

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

當使用者在未登出銀行帳戶的情況下點擊 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 屬性,用於控制 cookies 是否隨著跨站請求一起發送。它有三個可能的值:

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

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

實作範例:

使用自定義請求標頭

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

實作範例:

在前端:

在伺服器端:

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

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

對敏感操作進行重新驗證

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

實作建議:

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

總結

通過這次深入探討,我們希望你對 CSRF 攻擊有了更全面的了解。 我們不僅學到了 CSRF 的運作方式,還探討了各種有效的防禦措施。這些方法都能有效提高網頁應用程式的安全性。

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