Light hero background

Nonce 與 CSRF Token 差在哪?應用場景又是什麼?

December 20, 2024

為了防止網路攻擊,Nonce(Number Used Once)CSRF Token (Cross-Site Request Forgery Token) 是現代網站兩種常見且重要的防護機制。這兩者雖然都與網頁安全性相關,但其設計目標、解決的問題和應用場景卻各有不同。本文會介紹這兩種機制的運作方式,並探討它們的差異以及適用情境。

Nonce 是什麼?為什麼需要它?

Nonce 是一個僅使用一次的隨機字串,用於確保每個請求或操作的唯一性。它通常由伺服器生成,並附加到每個請求中。透過在伺服器端存儲並驗證 Nonce,能有效防止攻擊者攔截請求後重複執行,確保請求僅執行一次。

舉例來說,使用者在網頁表單中多次點擊提交按鈕可能導致多次訂單生成,而 Nonce 機制能阻止伺服器處理重複請求。同時也可以防止重放攻擊(Replay Attack),這類攻擊通常試圖利用攔截到的合法請求執行多次,造成系統不當操作。

Nonce 有點像是是活動入場券。每張票都有唯一的編號,僅能使用一次來進入活動場地。當票在入口被掃描後,系統會將其標記為已使用,確保相同的票無法再次使用進入。

Reduce the game from idea to excution

Nonce 的應用場景

場景 1: 避免表單重複提交

在需要提交訂單的場景中,用戶可能不小心多次點擊提交按鈕,而每次提交都會產生一個新的請求,伺服器在沒有驗證機制的情況下,可能會重複處理這些請求,進而導致多筆訂單或是重複執行的任務。

為了解決這個問題,可以使用 Nonce 確保每次表單提交請求的唯一性。伺服器端會生成一個隨機的 Nonce,並將其嵌入到表單中,用戶提交後,伺服器驗證該 Nonce 是否已被使用,若已使用,則拒絕該請求。

比如在購物網站,用戶在提交訂單後,可能不小心多次點擊「提交」按鈕。伺服器端利用 Nonce 驗證每次請求是否唯一,確保訂單不會被重複提交。

場景 1 實作

表單

<form method="POST" action="/submit-order">
  <input type="hidden" name="nonce" value="123456789abcdef">
  <input type="text" name="orderDetails">
  <button type="submit">提交訂單</button>
</form>

伺服器端檢查

if (isNonceValid(request.body.nonce)) {
    processOrder();
    invalidateNonce(request.body.nonce);
} else {
    throw new Error("Invalid nonce!");
}

場景 2: 防止重放攻擊

攻擊者可能攔截合法的 API 請求,並多次發送相同的請求以實現惡意操作。為了防止這類重放攻擊,可以使用 Nonce 確保每個請求的唯一性。伺服器通過檢查 Nonce 是否已被使用來判斷請求是否有效。

假設有一個執行扣款功能的 RESTful API,若扣款請求被攔截到,攔截者可以惡意發送同樣扣款請求多次。這時就需要 nonce 來確保最多只會被扣款一次。

場景 2 實作

Request

POST /transactions HTTP/1.1
Host: example.com
Content-Type: application/json
Authorization: Bearer <access_token>

{
    "nonce": "abcdef123456",
    "amount": 100.00,
    "account_id": "1234567890",
    "transaction_type": "deduction"
}

伺服器端

if (isNonceValid(request.body.nonce)) {
    executeTransaction(request.body.amount, request.body.account_id, request.body.transaction_type);
    invalidateNonce(request.body.nonce);
} else {
    throw new Error("Invalid or reused nonce!");
}

可以看到場景 1 與 場景 2 的伺服器端是一樣的邏輯,因為目的都是要避免重複的請求。

特別場景: 內容安全策略(CSP)

Nonce 在 Content Security Policy (CSP) 中的用法有點不同,主要是用於控制 inline script 或樣式的執行。伺服器會生成 Nonce,並將其同時包含在 CSP 標頭和授權的 <script><style> 標籤中。這個過程與先前介紹的 Nonce 機制類似,但驗證的動作發生在瀏覽器中。瀏覽器會強制執行 CSP 規則,確保只有帶有正確 Nonce 的腳本或樣式被執行,阻止未經授權的內容。

例如,一個顯示使用者特定數據的網頁可能需要動態生成的 inline JavaScript。透過在伺服器生成的 CSP 標頭和授權的腳本中嵌入 Nonce,只有預期的 script 會被執行,而未授權的 script 將被阻止。這確保了關鍵的 inline script 能夠安全地運行,同時避免頁面受到惡意 script 注入的威脅。

特別場景 CSP 實作

伺服器設置 CSP 標頭

Content-Security-Policy: script-src 'self' 'nonce-abcdef123456';

HTML

<script nonce="abcdef123456">
  console.log('This is a secure script.');
</script>

<script>
  console.log('This script will be blocked by CSP.');
</script>

結果

  • 僅有包含正確 Nonce 的 inline script 會被執行。
  • 其他 script 將被 CSP 攔截並阻止。
  • 最後只會印出 This is a secure script.

CSRF Token 是什麼?為什麼需要它?

CSRF Token(Cross-Site Request Forgery Token)是一種專門用於防範跨站請求偽造(CSRF)攻擊的安全措施。目的在於驗證每次請求是否來自用戶的合法操作,而非來自惡意網站的誘導請求。

CSRF 攻擊的典型場景是利用受害者的已登入狀態,在未經授權或不知情的情況下,通過受害者的瀏覽器向受信任的網站發送惡意請求。例如,攻擊者可能會偽造請求進行未經授權的資金轉帳、更改密碼或刪除用戶賬戶等高風險操作。

CSRF Token 通常由伺服器生成並與 session 綁定。伺服器將 Token 發送至用戶瀏覽器,並要求用戶在每次請求中附加此 Token。伺服器在接收請求時會驗證 Token 是否與用戶會話中的值匹配。如果 Token 無效或缺失,請求將被拒絕。

該機制通過驗證請求的合法性,阻止攻擊者利用跨站方式冒充用戶身份進行敏感操作,以提升應用的安全性。

CSRF Token 的應用場景

場景: 增加敏感操作的安全性

攻擊者可能利用用戶的已登錄狀態發起資金轉帳等高風險操作。為了防止這類情況,CSRF Token 是一種有效的驗證方式。

範例情境:用戶需通過 CSRF Token 保護資金轉帳請求。

實作

前端表單

<form method="POST" action="/transfer-funds">
  <input type="hidden" name="csrf_token" value="abcd1234efgh">
  <input type="number" name="amount" placeholder="轉帳金額">
  <input type="text" name="to_account" placeholder="收款帳號">
  <button type="submit">提交轉帳</button>
</form>

伺服器端

if (request.body.csrf_token === session.csrf_token) {
    processTransfer(request.body.amount, request.body.to_account);
} else {
    throw new Error("Invalid CSRF token!");
}

附註:CSRF 通常依賴於 session,因此有的 CSRF Token 會放在 HTTP 標頭(header)中,或是 <head> 下,也可能如範例一樣嵌入在隱藏的表單欄位中。實際存放位置並不關鍵,最重要的是在進行操作時,確保該 Token 能正確傳遞到伺服器,並由伺服器驗證其合法性,就能有效的確保請求的真實性。

總結

Nonce 與 CSRF Token 的差異比較

特性NonceCSRF Token
主要目標防止重放攻擊、表單重複提交防止跨站請求偽造攻擊
用法確保請求的唯一性驗證請求的合法性
實現層級常用於 API 或表單提交常用於 API 或表單提交
是否會重複使用不會重複使用(單次有效)可能會重複使用(如多次提交表單的 session 中)
  • Nonce 用在確保請求的唯一性,避免重複的請求,或搭配 CSP 確保合法 script 的執行。
  • CSRF Token 用在防範跨站請求偽造(Cross-Site Request Forgery),透過驗證每個請求中包含的隨機字串是否與伺服器生成的匹配,確保請求來自合法用戶。

Nonce 與 CSRF Token 是否可以一起使用?

可以,兩種機制是為了解決不同問題而存在的,並且使用上也不衝突。依據要解決的問題來實作即可。

參考資料: