如何在ASP.Net C#自定义Action过滤器中验证同域请求(弃用易伪造的UrlReferer)
ASP.NET C# 自定义Action过滤器实现同域请求验证(无需UrlReferer)
实现思路
UrlReferer字段易被伪造且浏览器可能不发送,因此采用Origin请求头+Cookie验证的组合方案:
- 跨域请求时浏览器会强制发送Origin头,且无法通过前端篡改,可直接验证是否匹配当前域名
- 同域简单请求(如GET/HEAD)可能不带Origin,此时通过检查当前站点的Cookie(浏览器仅会自动携带同域Cookie)辅助验证
自定义过滤器实现
创建继承自ActionFilterAttribute的过滤器类,重写OnActionExecuting方法实现验证逻辑:
using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Http; using System; using Microsoft.Extensions.Configuration; public class SameDomainValidationFilter : ActionFilterAttribute { private readonly string[] _allowedDomains; // 从配置读取允许的域名,支持多域名(用逗号分隔) public SameDomainValidationFilter(IConfiguration configuration) { var domains = configuration["AllowedDomains"]; if (string.IsNullOrEmpty(domains)) throw new InvalidOperationException("请在配置文件中设置AllowedDomains项"); _allowedDomains = domains.Split(',', StringSplitOptions.RemoveEmptyEntries); } public override void OnActionExecuting(ActionExecutingContext context) { var request = context.HttpContext.Request; var origin = request.Headers["Origin"].ToString(); // 验证Origin头(存在时) if (!string.IsNullOrEmpty(origin)) { var isAllowed = Array.Exists(_allowedDomains, domain => origin.Equals(domain.Trim(), StringComparison.OrdinalIgnoreCase)); if (!isAllowed) { context.Result = new Microsoft.AspNetCore.Mvc.ForbidResult("请求来源不合法"); return; } } else { // 无Origin时,验证是否携带同域Cookie(示例用Identity认证Cookie,可替换为自定义Cookie) var hasValidCookie = request.Cookies.ContainsKey(".AspNetCore.Identity.Application"); if (!hasValidCookie) { context.Result = new Microsoft.AspNetCore.Mvc.ForbidResult("请求来源验证失败"); return; } } base.OnActionExecuting(context); } }
配置与使用
1. 配置允许的域名
在appsettings.json中添加允许的域名(支持多个,逗号分隔):
{ "AllowedDomains": "https://yourdomain.com,https://sub.yourdomain.com,https://localhost:5001" }
2. 注册过滤器
全局注册(对所有API控制器生效)
在Program.cs中添加:
builder.Services.AddControllers(options => { options.Filters.Add<SameDomainValidationFilter>(); });
局部注册(仅对特定控制器/Action生效)
直接在目标控制器或Action上标记:
[ApiController] [Route("api/[controller]")] [ServiceFilter(typeof(SameDomainValidationFilter))] public class YourApiController : ControllerBase { [HttpGet] public IActionResult GetData() { return Ok("请求验证通过"); } }
注意事项
- 若需支持子域名通配(如
*.yourdomain.com),可修改Origin验证逻辑,用origin.EndsWith(".yourdomain.com")替代精确匹配 - 本地开发时记得将
https://localhost:端口加入AllowedDomains,避免被拦截 - Cookie验证可根据业务调整:若无需登录态,可自定义一个同域Cookie(前端页面加载时设置),后端验证该Cookie是否存在
内容的提问来源于stack exchange,提问作者Hassnain Balghari
相关产品推荐
相关产品推荐

