一尘不染

对抗Asp.Net WebApi的Angular,在服务器上实现CSRF

angularjs

我正在Angular.js中实现一个网站,该网站访问了ASP.NET WebAPI后端。

Angular.js具有一些内置功能,可帮助进行反csrf保护。在每个http请求上,它将查找名为“ XSRF-TOKEN”的cookie,并将其作为名为“
X-XSRF-TOKEN”的标头提交。

这取决于Web服务器能够在验证用户身份之后设置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");

有人能发现这种方法有任何明显(或不太明显)的问题吗?


阅读 306

收藏
2020-07-04

共1个答案

一尘不染

代码没有指出任何问题,因此我认为问题已经解决。

2020-07-04