防范跨网站请求伪造 (XSRF/CSRF) 攻击

Web 浏览器会随着对网站的每个请求自动发送cookie。例如在A网页中对B网页发送请求,浏览器就会自动带上B网页的cookie,如果B网页采用基于cookie的身份验证,A网页就能冒充用户给B网页发送请求。这种形式的攻击就是跨网站请求伪造(Cross-site request forgery, CSRF),也称为XSRF。

CSRF 攻击并不局限于利用 Cookie,基本身份验证和摘要式身份验证也容易受到攻击。 用户使用基本或摘要式身份验证登录后,浏览器会自动发送凭据,直到会话结束。

CSRF 攻击示例:

  1. 用户使用表单身份验证登录到 www.good-banking-site.example.com。 服务器对用户进行身份验证,并发出包含身份验证 cookie 的响应。如果此网站信任收到的任何带有有效身份验证cookie的请求,那么就会容易受到CSRF攻击。

  2. 用户访问恶意网站 www.bad-crook-site.example.com

    恶意网站 www.bad-crook-site.example.com 包含类似于以下示例的 HTML 表单:

    <h1>Congratulations! You're a Winner!</h1>
    <form action="https://www.good-banking-site.example.com/api/account" method="post">
        <input type="hidden" name="Transaction" value="withdraw" />
        <input type="hidden" name="Amount" value="1000000" />
        <input type="submit" value="Click to collect your prize!" />
    </form>
    

    表单的 action 将发送到www.good-banking-site.example.com网站。

  3. 用户点击提交按钮,浏览器发出请求,并自动包括所请求域www.good-banking-site.example.com 的身份验证cookie 。因此请求可以执行经过身份验证的用户可执行的任何操作。

除了用户点击按钮来提交表单外,恶意网站还可以通过以下方式执行攻击:

  • 运行自动提交表单的脚本。
  • 以 AJAX 请求形式发送表单提交。
  • 使用 CSS 隐藏表单。

防范跨网站请求伪造攻击

防范CSRF攻击最常用的方法是采用同步令牌模式(STP):

  • 服务器为每个用户会话生成一个随机且唯一的令牌发送到客户端。因为同源策略,其他网页不能读取到此令牌。
  • 发送请求时,客户端将令牌包含在请求头中发送回服务器进行验证。而恶意网站伪造此请求时,浏览器不会自动附加请求头。
  • 如果服务器收到的令牌与已认证用户的身份不符,那么该请求将被拒绝。

例如,ASP.NET Core MVC或Razor Pages会在页面中添加隐藏的表单域,其包含了防伪令牌:

<input name="__RequestVerificationToken" type="hidden" value="CfDJ8NrAkS ... s2-m9Yw">

发送表单请求时,将防伪令牌添加到表单字段或添加到RequestVerificationToken请求头发送给服务器。当请求标头和表单有效负载中都提供了防伪造令牌时,仅验证标头中的令牌。

另一种方式是服务器将防伪令牌添加到cookie中,客户端从cookie中读取防伪令牌添加到请求头发送请求。

ASP.NET Core 中的防伪造

Program.cs中调用以下 API 之一时,防伪造中间件将自动添加到容器:

最小API添加防伪造中间件

var builder = WebApplication.CreateBuilder();

builder.Services.AddAntiforgery();

var app = builder.Build();

app.UseAntiforgery();

app.MapGet("/", () => "Hello World!");

app.Run();

调用 AddAntiforgeryUseAntiforgery(IApplicationBuilder) 在 DI 中注册防伪造服务。

手动启用时,防伪造中间件必须在身份验证和授权中间件之后运行,以防止在用户未经身份验证时读取表单数据。

配置防伪造

Program.cs中配置AntiforgeryOptions

builder.Services.AddAntiforgery(options =>
{
    options.FormFieldName = "__RequestVerificationToken";
    options.HeaderName = "RequestVerificationToken";
    options.Cookie.Name = "XSRF-TOKEN";
});
选项 说明
Cookie 确定用于创建防伪造 Cookie 的设置。
FormFieldName 防伪造系统用于在视图中呈现防伪造令牌的隐藏表单域的名称。
HeaderName 防伪造系统使用的标头的名称。 如果为 null,则系统仅考虑表单数据。
SuppressXFrameOptionsHeader 指定是否禁止生成 X-Frame-Options 标头。 默认情况下,标头是使用值“SAMEORIGIN”生成的。 默认为 false

生成防伪造令牌

IAntiforgery 提供用于配置防伪功能的 API,可通过依赖注入获取IAntiforgery

示例:生成防伪令牌,并作为cookie在响应中发送:

app.UseRouting();

app.UseAuthorization();

var antiforgery = app.Services.GetRequiredService<IAntiforgery>();

app.Use((context, next) =>
{
    var requestPath = context.Request.Path.Value;

    if (string.Equals(requestPath, "/", StringComparison.OrdinalIgnoreCase)
        || string.Equals(requestPath, "/index.html", StringComparison.OrdinalIgnoreCase))
    {
        var tokenSet = antiforgery.GetAndStoreTokens(context);
        context.Response.Cookies.Append("XSRF-TOKEN", tokenSet.RequestToken!,
            new CookieOptions { HttpOnly = false });
    }

    return next(context);
});

前面的示例设置了一个名为 XSRF-TOKEN 的 Cookie。客户端可以读取此 Cookie,并将其值作为附加到 AJAX 请求的标头提供。

例如,Angular 包含内置的 XSRF 保护 ,默认情况下会读取名为 XSRF-TOKEN 的 Cookie。

要求防伪验证

ASP.NET Core 包含三个用于处理防伪造令牌的筛选器

ValidateAntiForgeryToken

ValidateAntiForgeryToken筛选器要求请求包含有效的防伪令牌,此筛选器可应用于Action、Controller或全局。

[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Index()
{
    // ...

    return RedirectToAction();
}

AutoValidateAntiForgeryToken

AutoValidateAntiforgeryToken筛选器仅要求不安全的HTTP方法请求包含有效的防伪令牌,以下HTTP方法发出的请求不需要令牌:

  • GET
  • HEAD
  • OPTIONS
  • TRACE

示例:

[AutoValidateAntiforgeryToken]
public class HomeController : Controller

全局设置此筛选器:

builder.Services.AddControllersWithViews(options =>
{
    options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
});

IgnoreAntiforgeryToken

如果 ValidateAntiForgeryToken 特性应用于控制器,则可以在Action用 IgnoreAntiforgeryToken 特性覆盖它。

IgnoreAntiforgeryToken筛选器用于消除指定Action或Controller对防伪令牌的要求。此筛选器将覆盖在更高级别指定的 ValidateAntiForgeryTokenAutoValidateAntiforgeryToken筛选器。

示例:

[IgnoreAntiforgeryToken]
public IActionResult IndexOverride()
{
    // ...

    return RedirectToAction();
}
posted @ 2025-08-14 09:18  酸豆角肉末  阅读(41)  评论(0)    收藏  举报