我有一个单页应用程序(用户加载了一堆HTML/JS,然后发出AJAX请求,而无需再次调用MVC-仅通过WebAPI)。在WebAPI中,我具有以下内容:
public sealed class WebApiValidateAntiForgeryTokenAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(
System.Web.Http.Controllers.HttpActionContext actionContext)
{
if (actionContext == null)
{
throw new ArgumentNullException(nameof(actionContext));
}
if (actionContext.Request.Method.Method == "POST")
{
string requestUri = actionContext.Request.RequestUri.AbsoluteUri.ToLower();
if (uriExclusions.All(s => !requestUri.Contains(s, StringComparison.OrdinalIgnoreCase))) // place some exclusions here if needed
{
HttpRequestHeaders headers = actionContext.Request.Headers;
CookieState tokenCookie = headers
.GetCookies()
.Select(c => c[AntiForgeryConfig.CookieName]) // __RequestVerificationToken
.FirstOrDefault();
string tokenHeader = string.Empty;
if (headers.Contains("X-XSRF-Token"))
{
tokenHeader = headers.GetValues("X-XSRF-Token").FirstOrDefault();
}
AntiForgery.Validate(!string.IsNullOrEmpty(tokenCookie?.Value) ? tokenCookie.Value : null, tokenHeader);
}
}
base.OnActionExecuting(actionContext); // this is where it throws
}
}
在Global.asax中注册:
private static void RegisterWebApiFilters(HttpFilterCollection filters)
{
filters.Add(new WebApiValidateAntiForgeryTokenAttribute());
filters.Add(new AddCustomHeaderFilter());
}
有时,我在日志中看到
The anti-forgery cookie token and form field token do not match
错误。发生这种情况时,tokenCookie.value
和tokenHeader
都不为空。在客户端,我所有的AJAX请求都使用以下内容:
beforeSend: function (request) {
request.setRequestHeader("X-XSRF-Token", $('input[name="__RequestVerificationToken"]').attr("value"););
},
使用Razor在我的SPA页面上一次生成 token :
@Html.AntiForgeryToken()
我在Web.config中设置了机器 key 。
是什么原因造成的?
更新
我刚刚查看了日志,有时也看到以下内容:
The provided anti-forgery token was meant for user "", but the current user is "someuser@domain.com". a few seconds ago
当用户在登录时刷新其SPA实例时,会发生这种情况。然后SPA由于某种原因(
User.Identity.IsAuthenticated
为true)将其拖放到登录页面而不是内页中-由于该错误,他们无法登录。刷新将它们拉回内部。不知道这意味着什么,但是我认为更多信息不会受到伤害。附录
https://security.stackexchange.com/questions/167064/is-csrf-protection-useless-with-ajax/167076#167076
最佳答案
我的回答将建议不要尝试基于AJAX调用中的 token 使用CSRF保护,而应依赖于Web浏览器的 native CORS功能。 Cross-Origin Request Blocked: The Same Origin Policy disallows reading
the remote resource at http://www.reuters.com/. (Reason: CORS header
‘Access-Control-Allow-Origin’ missing). Modern browsers support cross-site requests by implementing the Web
Applications (WebApps) Working Group's Access Control for Cross-Site
Requests standard. As long as the server is configured to allow requests from your web
application's origin, XMLHttpRequest will work. Otherwise, an
INVALID_ACCESS_ERR exception is thrown.
基本上,从浏览器到后端服务器的任何AJAX调用都将检查域的来源(也就是加载脚本的域)。如果这些域匹配(JS托管域==目标AJAX服务器域),则AJAX调用会正常执行,否则返回null
。
如果攻击者尝试在自己的服务器上托管恶意AJAX查询,则如果您的后端服务器没有允许他这样做的CORS策略,则该攻击将会失败(默认情况下就是这种情况)。
因此,就 native 而言, CSRF保护在AJAX调用中是无用的,您可以通过不尝试处理来降低的技术债务。
有关CORS - Mozilla Foundation的更多信息
代码示例-使用控制台检查器!
<html>
<script>
function reqListener () {
console.log(this.responseText);
}
var oReq = new XMLHttpRequest();
oReq.addEventListener("load", reqListener);
oReq.open("GET", "http://www.reuters.com/");
oReq.send();
</script>
</html>
运行它并查看安全性错误:
Mozilla对于Cross-site XMLHttpRequest实现非常清楚:
关于asp.net - 使用WebApi时,防伪Cookie token 和表单字段 token 不匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45389512/