Implementieren Sie im Winkel zu Asp.Net WebApi CSRF auf dem Server

Ich implementiere eine Website in Angular.js, die auf ein ASP.NET-WebAPI-Backend zugreift.

Angular.js verfügt über einige integrierte Funktionen, die beim Anti-Csrf-Schutz helfen. Bei jeder http-Anforderung wird nach einem Cookie mit dem Namen "XSRF-TOKEN" gesucht und als Header mit dem Namen "X-XSRF-TOKEN" gesendet.

Dies setzt voraus, dass der Webserver das XSRF-TOKEN-Cookie nach der Authentifizierung des Benutzers setzen und anschließend den X-XSRF-TOKEN-Header auf eingehende Anforderungen überprüfen kann.

DasEckige Dokumentation Zustände:

Um dies nutzen zu können, muss Ihr Server bei der ersten HTTP-GET-Anforderung ein Token in einem von JavaScript lesbaren Sitzungscookie namens XSRF-TOKEN festlegen. Bei nachfolgenden Non-GET-Anforderungen kann der Server überprüfen, ob das Cookie mit dem HTTP-Header X-XSRF-TOKEN übereinstimmt, und daher sicherstellen, dass nur JavaScript, das auf Ihrer Domain ausgeführt wird, das Token gelesen hat. Das Token muss für jeden Benutzer eindeutig sein und vom Server überprüft werden können (um zu verhindern, dass das JavaScript seine eigenen Token erstellt). Wir empfehlen, dass das Token aus Sicherheitsgründen ein Digest des Authentifizierungscookies Ihrer Site mit Salt ist.

Ich konnte keine guten Beispiele dafür für ASP.NET WebAPI finden, daher habe ich meine eigenen mit Hilfe von verschiedenen Quellen gerollt. Meine Frage ist - kann jemand etwas falsch mit dem Code sehen?

Zuerst habe ich eine einfache Hilfsklasse definiert:

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;
        }
    }
}

Dann habe ich die folgende Methode in meinem Berechtigungscontroller und rufe sie auf, nachdem ich FormsAuthentication.SetAuthCookie () aufgerufen habe:

    // 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);
    }

Dann habe ich ein benutzerdefiniertes Attribut, das ich Controllern hinzufügen kann, damit sie den csrf-Header überprüfen:

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);
    }
}

Zuletzt lösche ich das Csrf-Token, wenn sich der Benutzer abmeldet:

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

Kann jemand offensichtliche (oder nicht so offensichtliche) Probleme mit diesem Ansatz erkennen?

Antworten auf die Frage(4)

Ihre Antwort auf die Frage