令牌并不是为了阻止授权用户手动制作请求。该令牌确保用户以外的其他人不能使用 csrf 请求来伪造来自用户的请求。
您可以重复使用相同的令牌,因为如果实施得当,潜在的 CSRF 攻击者应该无法读取该值。这依赖于浏览器的同源策略,以确保第三方站点无法读取或提交相同的值。
如果您有任何漏洞,例如返回令牌的 json GET(最佳做法是返回的 JSON 数据仍应与帖子一起提交),那么令牌可能会被泄露。
https://docs.microsoft.com/en-us/aspnet/web-api/overview/security/preventing-cross-site-request-forgery-csrf-attacks
授权
关于来自经过身份验证的用户的潜在欺诈请求
您需要进行服务器端检查,以确保他仅将编辑发布到他有权编辑的帐户。例如,如果我拥有账户 A,并且我想向账户 B 汇款,那么服务器端检查将确保我拥有账户 A,因此有权将其资金发送到其他地方。如果我手工制作了从 B 向 A 发送资金的请求,服务器端检查应该通过查看帐户和所有者的数据库关系来确定我不是 B 的所有者。这称为授权。授权确保用户有权执行某项操作。这通常由定义表之间关系的业务规则规定,这些关系说明谁可以访问什么。
身份验证
唯一的另一个问题是确保我是我所说的我,因为如果我只是在请求中发布了一个用户 ID,我可以很容易地在浏览器中更改它。
当用户证明他是他所说的人时,通常通过提供用户 ID/密码,然后我们生成一个身份验证令牌。在 ASP.NET 中,此令牌是加密安全的,因此只有服务器具有生成和验证令牌所需的密钥信息。通常此令牌作为 cookie 保存。
身份验证和授权的结合确保我们知道用户是谁,并且在每个请求上使用我们定义授权的业务规则来检查操作是否有效。他可以手工制作无效请求并不重要,因为这些请求将无法通过服务器端授权。
想象一下这个简化的服务器端代码:
public void TransferFunds(TransferFundsRequest request)
{
var account = Database.GetAccount(request.SourceAccountId);
if(account.OwnerUserId != session.UserId)
{
throw UnauthorizedException("This user is not the owner of the source account in the transfer funds request.");
}
// continue with logic to transfer funds
}
CSRF
跨站点请求伪造是一个完全不同的问题。这是当授权用户的浏览器中加载的另一个站点尝试从用户的浏览器发送请求时。我访问的恶意第三方网站使用 javascript 或其他方法使我的浏览器从账户 A 向账户 C 发出 TransferFunds 请求。现在,如果我是账户 A 的所有者,从服务器的角度来看这是一个有效的请求. CSRF 令牌确保我们可以检测到用户不是从我们的服务器生成的表单发送请求,而是从某个第三方站点的表单或 URL 发送请求。
例如,如果请求的所有参数都可以编码在查询字符串中,我可以为 TransferFunds 请求制作一个 URL,并将其通过电子邮件发送给账户 A 所有者,并尝试诱使他们点击链接。如果用户碰巧登录了站点,那么我们的服务器就会认为是用户发送了请求。但是,如果我们在生成 HTML 输入表单时包含 anti-CSRF 令牌,那么令牌的缺失向我们证明了请求来自第三方制作的表单或 URL。