所有表单都应该在ASP.NET Web API中检查相同的防伪令牌吗



以下是场景:

Web API使用在Program.cs:中添加的防伪服务

builder.Services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");

用户想要编辑项目。因此,客户端通过调用:从API请求一个表单

[HttpGet("[action]")]
public IActionResult Edit([FromQuery] int id) 
{
var obj = _objService.GetObjOrDefault(id);
if (obj == null)
{
return NotFound();
}
var antiForgery = HttpContext.RequestServices.GetService<IAntiforgery>();
if (antiForgery != null)
{
var tokens = antiForgery.GetAndStoreTokens(HttpContext);
HttpContext.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken!, new CookieOptions { HttpOnly = false });
}

return new ObjectResult(obj);
}

用户填写表单。客户端将更新后的对象发送回API(头中包含防伪令牌(。客户端调用此API方法:

[HttpPut("[action]")]
[ValidateAntiForgeryToken]
public IActionResult Update([FromQuery] int id, [FromBody] SomeClass updated)
{
_objService.UpdateObj(id, obj);
}

ASP。NET自动检查防伪令牌是否有效。令人惊叹的但请稍等。客户端可以在应用[ValidateAntiForgeryToken]属性的所有其他API方法中重复使用相同的防伪令牌,似乎没有时间限制(?(。

我的问题是,你如何确保防伪代币是针对特定表格发送的,你应该这样做吗?如果客户端可以使用相同的防伪令牌填写任何表单,为什么不在用户登录时将其发送给客户端一次呢?你必须以某种方式清除或超时防伪代币吗?

我基本上遵循了这篇文章来实现防伪令牌,它是有效的,但我仍然不明白你应该如何实现它。

编辑:只要HTTP上下文(基本上是用户的当前URL(保持不变,客户端就可以在多个控制器上重复使用防伪令牌。你不会知道是哪个表格或哪个管理员给了他防伪令牌。

防伪令牌是有限的。它们只防止跨站点请求伪造(CSRF(攻击。通过实现防伪令牌,您可以证明请求是由查看您的页面的用户发送的,而不是恶意的。

同源策略(SOP(是一种在web浏览器中实现的安全功能。SOP可确保恶意站点(如www.cat.com(无法读取从API检索到的响应。但是,恶意站点可能会向API发送请求。默认情况下,用户的cookie(如会话ID(包含在发送到API的请求中,无论用户当前位于哪个域

由于SOP,只有使用您站点的客户端才能读取GET请求的响应。这就是为什么当用户使用例如GET api/something/edit请求表单时,我们会添加防伪令牌。恶意网站将无法读取响应中包含的防伪令牌。因此,当用户后来使用包括防伪令牌的PUT api/something/update时,我们知道更新请求是由能够读取GET请求响应的人发送的,并且当前正在浏览您的网站。

正如MS文档中所述,GET请求在理想情况下应该没有副作用。例如,GET请求不应该修改数据,因为它们可能是从恶意网站发送的。所有POST、PUT和DELETE请求都应该应用防伪令牌,即使在登录页面上也是如此。

但是,关于我最初的问题:假设用户请求GET api/something/edit?id=1,但随后发送请求PUT api/something/update?id=2[ValidateAntiForgeryToken]不会检查客户端是否确实更新了他最初请求的对象。您需要实现一些自定义逻辑来检查这一点,但通常情况下您不会麻烦这样做,因为您可以使用基于声明的授权,只需检查用户是否可以更新该对象。有了防伪令牌,你就知道用户在使用你的网站时正在执行操作,而不是恶意的。

TL:DR:为了回答我最初的问题;您应该为多个表单使用相同的防伪令牌吗&";。这其实并不重要。如果用户可以提供防伪令牌,他已经证明他是在查看您的页面时发送请求的,而不是恶意请求。最佳实践是在所有POST、PUT和DELETE请求中包含[ValidateAntiForgeryToken],同时确保GET请求没有任何副作用。您仍然需要检查用户是否可以更新他试图修改的项目,例如,通过使用基于声明的授权。

最新更新