.NET 8 Blazor独立账户认证下内部API的CSRF防护问询
Blazor WebApp(独立账户认证 + .NET 8)的内部API CSRF防护问题
我通过Blazor WebApp模板创建了一个自动渲染(Interactive Auto)且启用独立账户认证的.NET 8项目。
服务端新增了一个带[Authorize]特性的内部API控制器,包含POST方法;客户端通过Razor页面(带[Authorize],自动渲染模式)使用HttpClient调用该API的POST接口。
我想确认:这类项目会自动为内部API提供CSRF防护吗?还是需要额外配置来保障安全?
服务端代码:TestController.cs
namespace WebAppAutoIndividual.Controllers { [ApiController] [Route("api/test2")] [Authorize] public class Test2Controller : Controller { private readonly ITest2Service _service; public Test2Controller(ITest2Service service) { _service = service ?? throw new ArgumentNullException(nameof(service)); } [HttpGet] public DataTest[] Read() { var items = _service.Get().Result; return items; } [HttpPost] public void Create([FromBody] DataTest dto) { _service.Add(dto); } } }
客户端Razor页面:form-auto-controller.razor
@page "/form-auto-controller" @attribute [Authorize] @rendermode InteractiveAuto @using System.ComponentModel.DataAnnotations @using System.Net.Http @using WebAppAutoIndividual.Client.Services @inject ILogger<FormAutoController> Logger @inject ITest2Service Service <PageTitle>Formulaire avec Controleur avec rendu auto</PageTitle> <p>Mode de rendu : @(OperatingSystem.IsBrowser() ? "Wasm" : "Server")</p> <EditForm Model="Model" OnValidSubmit="SubmitAsync" FormName="StarshipClientAutoRender"> <DataAnnotationsValidator /> <ValidationSummary /> <label> Prénom : <InputText @bind-Value="Model!.FirstName" /> </label> <label> Nom : <InputText @bind-Value="Model!.Name" /> </label> <button type="submit">Submit</button> </EditForm> @if (allModels == null) { <p>Loading ...</p> } else { <label> je suis @serviceName</label> <button @onclick="Refresh">Refresh</button> @foreach(DataTest i in allModels) { <p>@i.Name, @i.FirstName</p> } } @code { [SupplyParameterFromForm] public DataTest? Model { get; set; } private DataTest[] allModels { get; set; } = null; private DateTime DateTimeRefresh = DateTime.Now; private string serviceName = "aucun"; protected override async Task OnInitializedAsync() { Model ??= new(); serviceName = Service.Whois(); allModels = await Service.Get(); } protected async Task Refresh() { allModels = await Service.Get(); DateTimeRefresh = DateTime.Now; } private async Task SubmitAsync() { Logger.LogInformation("Prénom Nom = {fisrtname} {name}", Model?.FirstName, Model?.Name); if (Model != null) { await Service.Add(Model); } } }
客户端Http服务:Test2ProxyService.cs
namespace WebAppAutoIndividual.Client.Services; public class Test2ProxyService : ITest2Service { private readonly HttpClient _http; public Test2ProxyService(HttpClient http) { _http = http; } public string Whois() { return nameof(Test2ProxyService); } public async Task Add(DataTest test) { Console.WriteLine("Service 2 POST depuis le client"); await _http.PostAsJsonAsync("/api/test2", test); } public async Task<DataTest[]> Get() { Console.WriteLine("Service 2 GET test depuis le client"); var result = await _http.GetFromJsonAsync<DataTest[]>("/api/test2"); return result; } }
回答
针对你的场景,分两种运行模式说明CSRF防护情况:
1. Interactive Server模式运行时
此时Blazor Server会自动处理CSRF防护:
- 框架自动生成并验证
XSRF-TOKENCookie和RequestVerificationToken请求头 - 注入的
HttpClient会自动携带这些令牌,无需额外配置 - 你的API控制器继承了
Controller,默认会验证POST/PUT/DELETE等非安全请求的CSRF令牌,当前代码已具备防护能力
2. Interactive WebAssembly模式运行时
Wasm模式下的CSRF防护需要额外配置:
- 独立账户认证体系不会自动为Wasm客户端的API请求添加CSRF令牌
- 需手动配置并实现令牌的获取与携带:
- 在服务端
Program.cs中配置CSRF服务:builder.Services.AddAntiforgery(options => { options.HeaderName = "X-XSRF-TOKEN"; options.Cookie.Name = "XSRF-TOKEN"; options.Cookie.SecurePolicy = CookieSecurePolicy.Always; // 生产环境建议启用 }); - 在API控制器的POST方法上添加
[ValidateAntiForgeryToken]特性(或全局配置验证):[HttpPost] [ValidateAntiForgeryToken] public void Create([FromBody] DataTest dto) { _service.Add(dto); } - 在Wasm客户端的Http服务中先获取CSRF令牌,再发起请求:
同时在服务端新增获取令牌的API端点:public async Task Add(DataTest test) { // 获取CSRF令牌 var tokenResponse = await _http.GetAsync("/api/antiforgery/token"); tokenResponse.EnsureSuccessStatusCode(); var token = await tokenResponse.ReadFromJsonAsync<AntiforgeryTokenResponse>(); // 添加令牌到请求头 _http.DefaultRequestHeaders.Add("X-XSRF-TOKEN", token.RequestToken); Console.WriteLine("Service 2 POST depuis le client"); await _http.PostAsJsonAsync("/api/test2", test); }[ApiController] [Route("api/antiforgery")] public class AntiforgeryController : Controller { private readonly IAntiforgery _antiforgery; public AntiforgeryController(IAntiforgery antiforgery) { _antiforgery = antiforgery; } [HttpGet("token")] public IActionResult GetToken() { var tokens = _antiforgery.GetAndStoreTokens(HttpContext); return Ok(new { RequestToken = tokens.RequestToken }); } }
- 在服务端
3. Interactive Auto模式的注意事项
Auto模式会根据场景切换Server/Wasm模式,需同时兼容两种配置:
- 保留Server模式的自动防护逻辑
- 添加Wasm模式所需的CSRF配置与令牌获取代码
- 可通过
OperatingSystem.IsBrowser()判断运行环境,区分处理逻辑
内容的提问来源于stack exchange,提问作者Sébastien Foucher
相关产品推荐
相关产品推荐

