.net mvc全局拦截CSRF跨站点攻击
开发中如果不想每个页面都验证CSRF跨站点攻击,可以按以下方法添加拦截器
1. 添加api请求拦截器
/// <summary>
/// Api拦截
/// </summary>
public class ApiPermissionFilter : System.Web.Http.Filters.ActionFilterAttribute
{
public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext filterContext)
{
try
{
var request = filterContext.Request;
if (request.Method != HttpMethod.Get && request.Method != HttpMethod.Post)
return;
var antiForgeryCookie = HttpContext.Current.Request.Cookies[AntiForgeryConfig.CookieName];
var cookieValue = antiForgeryCookie != null ? antiForgeryCookie.Value : null;
var heads = request.Headers.GetValues("__RequestVerificationToken");
if (heads.Count() < 1)
{
filterContext.Response = new System.Net.Http.HttpResponseMessage(HttpStatusCode.Forbidden);
return;
}
string token = heads.FirstOrDefault();
////从cookies 和 Headers 中 验证防伪标记
try
{
AntiForgery.Validate(cookieValue, token);
}
catch (Exception ex)
{
filterContext.Response = new System.Net.Http.HttpResponseMessage(HttpStatusCode.Forbidden);
return;
}
base.OnActionExecuting(filterContext);
}
catch
{
filterContext.Response = new System.Net.Http.HttpResponseMessage(HttpStatusCode.NotFound);
}
}
}
2. WebApiConfig.cs添加
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Filters.Add(new ApiPermissionFilter());
}
}
3. cshtml页面添加,最好在母版页添加
@Html.AntiForgeryToken()
@Html.ValidationSummary(true)
4. 新建 com.antiForgery.js文件,并在页面引入,该脚本目前我已经实现了post和get请求自动加入参数__RequestVerificationToken,脚本下载地址:https://download.****.net/download/a506602491/12372800
5. 添加普通Action请求的验证(非api)LoginActionFilter.cs
/// <summary>
/// 验证防伪标记,防止非法访问
/// </summary>
public class LoginActionFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var request = filterContext.HttpContext.Request;
if (request.HttpMethod != WebRequestMethods.Http.Post && request.HttpMethod != WebRequestMethods.Http.Get)
return;
if (filterContext.HttpContext.Request.HttpMethod == WebRequestMethods.Http.Post || request.IsAjaxRequest())
{
var antiForgeryCookie = request.Cookies[System.Web.Helpers.AntiForgeryConfig.CookieName];
var cookieValue = antiForgeryCookie != null ? antiForgeryCookie.Value : null;
string token = !string.IsNullOrWhiteSpace(request.Headers["__RequestVerificationToken"]) ? request.Headers["__RequestVerificationToken"] : request.Form["__RequestVerificationToken"];
if (string.IsNullOrWhiteSpace(token) && (request.UrlReferrer != null))
{
filterContext.Result = new ContentResult() { Content = "非法访问" };
filterContext.HttpContext.Response.StatusCode = 404;
}
////从cookies 和 Headers 中 验证防伪标记
try
{
//string openValidateUrl = "www.baidu.com";
////如果允许访问,则在启用下面判断
//if (request.UrlReferrer != null || openValidateUrl.Contains(request.CurrentExecutionFilePath.ToLower()))
//{
// base.OnActionExecuting(filterContext);
// return;
//}
//else
//{
// AntiForgery.Validate(cookieValue, token);
//}
AntiForgery.Validate(cookieValue, token);
}
catch (Exception ex)
{
filterContext.Result = new ContentResult() { Content = "非法访问" };
filterContext.HttpContext.Response.StatusCode = 404;
}
}
base.OnActionExecuting(filterContext);
}
}
6. FilterConfig.cs添加,如果没有就自己新建一个
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new LoginActionFilter());
}
}
7.global文件的Application_Start加入
protected void Application_Start()
{
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
}
完成上面工作后每次POST和GET请求页面都会添加__RequestVerificationToken的参数,并且会触发LoginActionFilter和ApiPermissionFilter两个拦截器