ASP.NET Core+Angular项目如何用ValidateAntiForgeryToken防范CSRF攻击
问题解答
1. 你当前的架构是否需要CSRF防护?
你采用的JWT token存在localStorage、请求时携带Authorization头的认证方式,天然免疫常规CSRF攻击。
CSRF的核心原理是恶意网站发起的跨站请求会被浏览器自动带上目标站点的cookie,但localStorage的存储内容不会被跨站请求自动读取/携带,恶意站点构造的请求根本拿不到你存在localStorage里的认证token,自然过不了后端的身份校验,所以默认状态下你不需要额外做CSRF防护。
2. 为什么加[ValidateAntiForgeryToken]后接口无法访问?
ASP.NET Core的[ValidateAntiForgeryToken]特性默认面向Razor表单场景,校验逻辑要求请求同时携带:
- 后端写入浏览器的防伪cookie
- 请求头/表单参数里对应的防伪token值
你当前的前端请求既没有收到后端返回的防伪cookie,也没有在请求里携带对应的防伪头,自然会被校验逻辑拦截,导致接口访问失败。
3. 如果要开启CSRF防护,如何配置?
如果你确实有场景需要叠加CSRF防护(比如部分接口同时支持cookie认证),可以按如下步骤配置前后端:
后端(ASP.NET Core 3.1)配置
- 注册防伪服务,和Angular的默认请求头适配
services.AddAntiforgery(options => { // 和Angular提交的头名保持一致 options.HeaderName = "X-XSRF-TOKEN"; // 允许前端JS读取cookie(不能设为HttpOnly) options.Cookie.HttpOnly = false; // 生产环境如果是HTTPS建议开启 options.Cookie.SecurePolicy = CookieSecurePolicy.Always; // 跨域场景下根据你的域名调整SameSite规则 options.Cookie.SameSite = SameSiteMode.Strict; });
- 在登录接口(或全局中间件)中注入
IAntiforgery服务,生成防伪token并写入响应cookie
public class LoginController : ControllerBase { private readonly IAntiforgery _antiforgery; public LoginController(IAntiforgery antiforgery) { _antiforgery = antiforgery; } [HttpPost] public IActionResult Login([FromBody] LoginRequest request) { // 原有登录校验逻辑,生成JWT返回 // 写入防伪cookie _antiforgery.GetAndStoreTokens(HttpContext); return Ok(new { Token = "your_jwt_token" }); } }
- 跨域场景下需要在CORS配置中允许
X-XSRF-TOKEN头,并且允许前端携带凭证。
前端(Angular 8.2.11)配置
Angular内置了XSRF拦截器,不需要自行编写拦截逻辑,只要在根模块中配置即可:
- 在
app.module.ts中导入并配置HttpClientXsrfModule
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { HttpClientModule, HttpClientXsrfModule } from '@angular/common/http'; import { AppComponent } from './app.component'; @NgModule({ declarations: [AppComponent], imports: [ BrowserModule, HttpClientModule, // 匹配后端的防伪cookie名和头名,ASP.NET Core默认的防伪cookie名为.XSRF-TOKEN HttpClientXsrfModule.withOptions({ cookieName: '.XSRF-TOKEN', headerName: 'X-XSRF-TOKEN' }) ], bootstrap: [AppComponent] }) export class AppModule { }
- 跨域场景下需要给所有请求添加
withCredentials: true配置,你可以选择每个请求单独加,或者编写全局拦截器统一添加:
// 单次请求配置示例 this.http.post('/api/protected-endpoint', postData, { withCredentials: true }).subscribe(res => { /* 处理响应 */ });
完成以上配置后,你的接口添加[ValidateAntiForgeryToken]属性即可正常访问。
内容的提问来源于stack exchange,提问作者For Comment
相关产品推荐
相关产品推荐

