Angular 对抗 Asp.Net WebApi,在服务器上实现 CSRF [英] Angular against Asp.Net WebApi, implement CSRF on the server

查看:21
本文介绍了Angular 对抗 Asp.Net WebApi,在服务器上实现 CSRF的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm implementing a website in Angular.js, which is hitting an ASP.NET WebAPI backend.

Angular.js 有一些内置功能来帮助进行反 csrf 保护.在每个 http 请求中,它会寻找一个名为XSRF-TOKEN"的 cookie 并将其作为一个名为X-XSRF-TOKEN"的标头提交.

Angular.js has some in-built features to help with anti-csrf protection. On each http request, it will look for a cookie called "XSRF-TOKEN" and submit it as a header called "X-XSRF-TOKEN" .

这依赖于网络服务器能够在对用户进行身份验证后设置 XSRF-TOKEN cookie,然后检查传入请求的 X-XSRF-TOKEN 标头.

This relies on the webserver being able to set the XSRF-TOKEN cookie after authenticating the user, and then checking the X-XSRF-TOKEN header for incoming requests.

Angular 文档指出:

要利用这一点,您的服务器需要在第一个 HTTP GET 请求时在名为 XSRF-TOKEN 的 JavaScript 可读会话 cookie 中设置一个令牌.在随后的非 GET 请求中,服务器可以验证 cookie 是否与 X-XSRF-TOKEN HTTP 标头匹配,因此请确保只有在您的域上运行的 JavaScript 才能读取令牌.令牌对于每个用户必须是唯一的,并且必须可由服务器验证(以防止 JavaScript 组成自己的令牌).我们建议该令牌是您网站的身份验证 cookie 的摘要,并添加了盐以提高安全性.

To take advantage of this, your server needs to set a token in a JavaScript readable session cookie called XSRF-TOKEN on first HTTP GET request. On subsequent non-GET requests the server can verify that the cookie matches X-XSRF-TOKEN HTTP header, and therefore be sure that only JavaScript running on your domain could have read the token. The token must be unique for each user and must be verifiable by the server (to prevent the JavaScript making up its own tokens). We recommend that the token is a digest of your site's authentication cookie with salt for added security.

我找不到任何适用于 ASP.NET WebAPI 的好的示例,因此我在各种来源的帮助下推出了自己的示例.我的问题是 - 任何人都可以看出代码有什么问题吗?

I couldn't find any good examples of this for ASP.NET WebAPI, so I've rolled my own with help from various sources. My question is - can anyone see anything wrong with the code?

首先我定义了一个简单的辅助类:

First I defined a simple helper class:

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() 后调用它:

Then I have the following method in my authorisation controller, and I call it after I call 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 标头:

Then I have a custom attribute which I can add to controllers to make them check the csrf header:

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 令牌:

Lastly, I clear the Csrf token when the user logs out:

HttpContext.Current.Response.Cookies.Remove("XSRF-TOKEN");

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

Can anyone spot any obvious (or not-so-obvious) problems with that approach?

推荐答案

代码中没有指出任何问题,所以我认为问题已得到解答.

Haven't had any problems pointed out with the code, so I consider the question answered.

这篇关于Angular 对抗 Asp.Net WebApi,在服务器上实现 CSRF的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆