Angular对抗Asp.Net WebApi,在服务器上实现CSRF
Angular对抗Asp.Net WebApi,在服务器上实现CSRF
我正在使用Angular.js实现一个网站,该网站与后端的ASP.NET WebAPI进行交互。
Angular.js具有一些内置功能,可以帮助防止跨站请求伪造(anti-csrf)攻击。在每个http请求中,它会查找名为“XSRF-TOKEN”的cookie,并将其提交为名为“X-XSRF-TOKEN”的头文件。
这依赖于Web服务器在验证用户身份后能够设置XSRF-TOKEN cookie,并检查传入请求的X-XSRF-TOKEN头文件。
Angular文档中提到:
为了利用这一点,您的服务器需要在第一个HTTP GET请求中设置一个名为XSRF-TOKEN的JavaScript可读会话cookie中的令牌。在随后的非GET请求中,服务器可以验证cookie是否与X-XSRF-TOKEN HTTP头文件匹配,从而确保只有在您的域上运行的JavaScript才能读取该令牌。该令牌必须对每个用户都是唯一的,并且服务器必须能够验证该令牌(以防止JavaScript编写自己的令牌)。我们建议该令牌是您网站身份验证cookie的摘要,并带有盐以增加安全性。
我找不到任何关于ASP.NET WebAPI的好例子,所以我参考了各种来源来实现自己的代码。我的问题是-有人能看到代码中的任何问题吗?
首先,我定义了一个简单的帮助类:
public class CsrfTokenHelper { const string ConstantSalt = "<一个随机字符串>"; public string GenerateCsrfTokenFromAuthToken(string authToken) { return GenerateCookieFriendlyHash(authToken); } public bool DoesCsrfTokenMatchAuthToken(string csrfToken, string authToken) { return csrfToken == GenerateCookieFriendlyHash(authToken); } private static string GenerateCookieFriendlyHash(string authToken) { using (var sha = SHA256.Create()) { var computedHash = sha.ComputeHash(Encoding.Unicode.GetBytes(authToken + ConstantSalt)); var cookieFriendlyHash = HttpServerUtility.UrlTokenEncode(computedHash); return cookieFriendlyHash; } } }
然后,在我的授权控制器中,我有以下方法,并在调用FormsAuthentication.SetAuthCookie()之后调用它:
// http://www.asp.net/web-api/overview/security/preventing-cross-site-request-forgery-(csrf)-attacks // http://docs.angularjs.org/api/ng.$http private void SetCsrfCookie() { var authCookie = HttpContext.Current.Response.Cookies.Get(".ASPXAUTH"); Debug.Assert(authCookie != null, "authCookie != null"); var csrfToken = new CsrfTokenHelper().GenerateCsrfTokenFromAuthToken(authCookie.Value); var csrfCookie = new HttpCookie("XSRF-TOKEN", csrfToken) {HttpOnly = false}; HttpContext.Current.Response.Cookies.Add(csrfCookie); }
然后,我有一个自定义属性,可以将其添加到控制器中以使其检查csrf头:
public class CheckCsrfHeaderAttribute : AuthorizeAttribute { // http://stackoverflow.com/questions/11725988/problems-implementing-validatingantiforgerytoken-attribute-for-web-api-with-mvc protected override bool IsAuthorized(HttpActionContext context) { // get auth token from cookie var authCookie = HttpContext.Current.Request.Cookies[".ASPXAUTH"]; if (authCookie == null) return false; var authToken = authCookie.Value; // get csrf token from header var csrfToken = context.Request.Headers.GetValues("X-XSRF-TOKEN").FirstOrDefault(); if (String.IsNullOrEmpty(csrfToken)) return false; // Verify that csrf token was generated from auth token // Since the csrf token should have gone out as a cookie, only our site should have been able to get it (via javascript) and return it in a header. // This proves that our site made the request. return new CsrfTokenHelper().DoesCsrfTokenMatchAuthToken(csrfToken, authToken); } }
最后,在用户退出时,我清除Csrf令牌:
HttpContext.Current.Response.Cookies.Remove("XSRF-TOKEN");
有人能发现该方法中的任何明显(或不明显)问题吗?