在.net framework mvc 中,時常處理到 XSRF/CSRF 的資安問題,這邊記錄一下使用 axios + filter 的作法。
Step1: 新增一個Filter
public class GlobalAntiForgeryTokenFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
try
{
if (filterContext == null)
{
throw new ArgumentNullException("fail");
}
// 如果有AllowAnonymous要忽略驗證,就使用這一段
object[] controllerAttributes = filterContext.Controller.GetType().GetCustomAttributes(true);
object[] actionAttributes = filterContext.ActionDescriptor.GetCustomAttributes(true);
if (controllerAttributes.Any(p => p.ToString().Contains("AllowAnonymousAttribute")) ||
actionAttributes.Any(p => p.ToString().Contains("AllowAnonymousAttribute")))
{
return;
}
// 驗證AntiForgeryToken
var httpMethod = filterContext.HttpContext.Request.HttpMethod.ToUpper();
if (httpMethod == "POST" &&
filterContext.HttpContext.Request.IsAjaxRequest() == true)
{
var httpContext = filterContext.HttpContext;
var cookie = httpContext.Request.Cookies[AntiForgeryConfig.CookieName];
AntiForgery.Validate(cookie != null ? cookie.Value : null, httpContext.Request.Headers["__RequestVerificationToken"]);
}
//base.OnActionExecuting(filterContext);
}
catch (Exception)
{
filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new { action = "Logout", controller = "Account" }));
return;
}
base.OnActionExecuting(filterContext);
}
}
Step2: 在FilterConfig中,註冊該Filter
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
// 這邊加入自訂的驗證過濾器
filters.Add(new GlobalAntiForgeryTokenFilter);
}
}
Step3: 在前端使用Antiforgery,並使用 axios 的 Post 方法
<body>
<!-- 這邊加入 AntiForgeryToken -->
@Html.AntiForgeryToken()
<div>TODO...<div>
<!-- 這邊加入 cdn axios -->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
// 取得AntiForgeryToken方法
function getAntiForgeryToken() {
var token = document.querySelector('input[name="__RequestVerificationToken"]').value;
return token;
}
// 以下為Post
axios.post(
url, // 'Home/GetData'
data, // { id: 1 }
{
'withCredentials': true,
'headers': {
'Content-Type': 'application/json;charset=UTF-8',
'X-Requested-With': 'XMLHttpRequest', // For IsAjaxRequest()
__RequestVerificationToken: getAntiForgeryToken(), // 這邊加入 AntiForgeryToken
},
},
).then(resp => {
// TODO...
}).catch(err => {
// TODO...
})
</script>
</body>