关于 Nonce 和 CSRF Token 的区别、用例以及工作原理
为了防范网络攻击,**Nonce(一次性使用的数字)**和**CSRF Token(跨站请求伪造令牌)**是现代网站常用且重要的两种安全机制。虽然两者都与网络安全有关,但它们的设计目标、解决的问题和应用场景却截然不同。本文将介绍这两种机制的工作原理、它们的区别以及它们各自的适用场景。
什么是 Nonce?为什么我们需要它?
**nonce** 是随机生成的字符串,仅使用一次,以确保每个请求或操作的唯一性。它通常由服务器生成并随每个请求一起提供。通过在服务器上存储和验证 nonce,可以有效防止攻击者拦截和重新执行请求,确保每个请求仅执行一次。
例如,当用户在 Web 表单中多次意外单击“提交”按钮时,可能会导致创建多个订单。nonce 机制可防止服务器处理重复请求。它还可以防止重放攻击,重放攻击会尝试利用拦截的合法请求执行多个操作,从而导致未经授权的操作。
**活动门票** 是 nonce 的一个好比喻。每张门票都有一个唯一的编号,只能使用一次才能进入活动。一旦在入口处扫描,系统就会将其标记为已使用,确保同一张门票不能再次使用。同样,nonce 可确保每个请求都是唯一的,不能被复制或恶意重复使用。

Nonce 的使用案例
场景 1:防止重复提交表单
在需要提交订单的场景中,用户可能会不小心点击了多次提交按钮,从而产生多次请求,如果没有验证机制,服务端可能会处理这些重复的请求,导致多个订单或任务被重复执行。
为了解决这个问题,可以使用 nonce 来确保每次表单提交的唯一性。服务器会生成一个随机 nonce 并将其嵌入到表单中。当用户提交表单时,服务器会验证该 nonce 是否已被使用。如果已经使用,则拒绝该请求。
以一个购物网站为例,用户在提交订单后可能会无意中多次点击“提交”按钮。服务器使用随机数来验证每个请求的唯一性,确保订单不会被多次提交。
方案 1 实施
形式:
服务器验证:
if (isNonceValid(request.body.nonce)) { processOrder(); invalidateNonce(request.body.nonce); } else { throw new Error("Invalid nonce!"); }
场景 2:防止重放攻击
攻击者可能会拦截合法的 API 请求,并出于恶意目的多次发送相同的请求。为了防止此类重放攻击,nonce 可以确保每个请求都是唯一的。服务器会检查 nonce 是否已被使用来确定请求的有效性。
通过重复发送相同的扣款请求,执行扣款的 RESTful API 可能会被恶意利用。Nonce 可确保请求最多执行一次。
方案 2 实施
要求:
POST /transactions HTTP/1.1 Host: example.com Content-Type: application/json Authorization: Bearer{ "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!"); }
特殊场景:内容安全策略(CSP)
内容安全策略 (CSP) 中,nonce 有特定用途,可为 Web 应用程序提供强大的保护。**CSP nonce** 是一个随机生成的字符串,仅使用一次,用于控制内联脚本或样式的执行。它由服务器生成,并包含在 CSP 标头和授权的 `
For example, a webpage displaying user-specific data may require dynamically generated inline JavaScript. By embedding a nonce in the server-generated CSP header and the authorized scripts, only the intended scripts are executed, while unauthorized ones are blocked. This ensures critical inline scripts can run safely without exposing the page to malicious script injections.
Special Scenario Implementation
Server-Set CSP Header:
Content-Security-Policy: script-src 'self' 'nonce-abcdef123456';
HTML Page:
**Result**:
What is a CSRF Token? Why do we need it?
A CSRF Token (Cross-Site Request Forgery Token) is a security measure designed to prevent cross-site request forgery (CSRF) attacks. Its purpose is to verify that each request comes from the user's legitimate operation rather than a malicious site's induced request.
A typical CSRF attack exploits the victim's logged-in state to send malicious requests to a trusted website without the victim's authorization or knowledge. For example, an attacker might forge a request to transfer funds, change passwords, or delete user accounts.
The CSRF Token is usually generated by the server and bound to the session. The server sends the token to the user's browser and requires the user to include this token in every request. Upon receiving the request, the server verifies whether the token matches the value stored in the user's session. If the token is invalid or missing, the request is rejected.
This mechanism verifies the legitimacy of requests, preventing attackers from impersonating users through cross-site methods to perform sensitive operations, thus enhancing application security.

Use Cases for CSRF Tokens
Scenario: Enhance Security for Sensitive Actions
Attackers may exploit a user's logged-in state to initiate high-risk actions like transferring funds. To prevent such situations, a CSRF Token serves as an effective validation method.
Users must include a CSRF Token to protect fund transfer requests.
Implementation
Form:
Server Validation:
if (request.body.csrf_token === session.csrf_token) { processTransfer(request.body.amount, request.body.to_account); } else { throw new Error("Invalid CSRF token!"); }
Summary
Differences Between Nonce and CSRF Token
Can Nonce and CSRF Tokens Be Used Together?
Yes, these mechanisms address different issues and can be used together without conflict. Implementation depends on the specific problem you aim to solve.