【发布时间】:2013-03-12 13:18:06
【问题描述】:
我正在使用 Angular.js 实现一个网站,该网站正在访问 ASP.NET WebAPI 后端。
Angular.js 有一些内置功能可以帮助进行反 csrf 保护。在每个 http 请求中,它都会查找一个名为“XSRF-TOKEN”的 cookie,并将其作为一个名为“X-XSRF-TOKEN”的标头提交。
这依赖于网络服务器能够在验证用户身份后设置 XSRF-TOKEN cookie,然后检查传入请求的 X-XSRF-TOKEN 标头。
要利用这一点,您的服务器需要在第一次 HTTP GET 请求时在名为 XSRF-TOKEN 的 JavaScript 可读会话 cookie 中设置一个令牌。在随后的非 GET 请求中,服务器可以验证 cookie 是否与 X-XSRF-TOKEN HTTP 标头匹配,因此确保只有在您的域上运行的 JavaScript 才能读取该令牌。每个用户的令牌必须是唯一的,并且必须可由服务器验证(以防止 JavaScript 组成自己的令牌)。我们建议该令牌是您网站的身份验证 cookie 的摘要,并带有盐以增加安全性。
我找不到任何适用于 ASP.NET WebAPI 的好的示例,因此我在各种来源的帮助下自行开发。我的问题是 - 任何人都可以看到代码有什么问题吗?
首先我定义了一个简单的辅助类:
public class CsrfTokenHelper
{
const string ConstantSalt = "<ARandomString>";
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");
谁能发现这种方法有任何明显(或不太明显)的问题?
【问题讨论】:
-
我也在尝试解决这个问题,并且想知道当攻击者都可以更改它们时比较两个 cookie 是否可以?如果你的盐被发现了,那么这不会受到损害吗?
-
BenCr,只有在我的域上运行的 javascript 才能读取 cookie 并将其放入标头中。所以如果有恶意网站导致浏览器向我的网站提交请求,该请求将没有标头,因此它将拒绝该请求。
-
你能解释一下你在这里描述的解决方案的结果吗?它是如何失败的?还是您要我们找出安全漏洞?
-
只是在寻找评论。它不会失败(AFAIK)
-
对于所有未来的用户,这是一个有用的链接,以防您正在使用 Asp.net MVC and AngularJs
标签: javascript asp.net angularjs asp.net-web-api csrf