Angulaire contre Asp.Net WebApi, de mettre en œuvre CSRF sur le serveur

Je me suis mise en œuvre d'un site web Angular.js qui frappe un ASP.NET WebAPI backend.

Angular.js a quelques fonctionnalités intégrées pour aider avec des anti-csrf de protection. Sur chaque requête http, il va chercher un cookie appelé "XSRF-TOKEN" et de le présenter comme un en-tête "X-XSRF-JETON" .

Cela repose sur le serveur web capable de définir la XSRF-JETON de cookie après l'authentification de l'utilisateur, puis la vérification de la X-XSRF-JETON-tête pour les requêtes entrantes.

La Angulaire de la documentation états:

À prendre avantage de cela, votre serveur doit mettre un jeton dans un JavaScript lisible cookie de session appelé XSRF-JETON sur la première requête HTTP GET. Sur les non-demandes GET le serveur peut vérifier que le témoin correspond à X-XSRF-JETON en-tête HTTP, et donc être sûr que le code JavaScript s'exécutant sur votre nom de domaine pourrait avoir lu le jeton. Le jeton doit être unique pour chaque utilisateur et doit être vérifiable par le serveur (pour éviter le JavaScript de faire ses propres jetons). Nous recommandons que le jeton est un condensé de votre site cookie d'authentification avec le sel pour plus de sécurité.

Je ne pouvais pas trouver tout de bons exemples de ce pour ASP.NET WebAPI, donc j'ai roulé mon propre avec l'aide de diverses sources. Ma question est, peut-on voir quelque chose de mal avec le code?

J'ai d'abord défini une simple classe helper:

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

Puis j'ai la méthode suivante dans mon autorisation du contrôleur, et je l'appelle après j'appelle 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);
    }

Ensuite, j'ai un attribut personnalisé qui je peux ajouter des contrôleurs de les faire vérifier le csrf en-tête:

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

Enfin, je effacer le jeton Csrf lorsque l'utilisateur se déconnecte:

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

Quelqu'un peut-il repérer toute évidente (ou pas si évident) problèmes avec cette approche?

  • Je suis en train d'essayer de trouver une solution à ce que le bien et vous demandez-vous si l'on compare les deux témoins est d'accord quand ils ont tous deux peuvent être modifiés par un attaquant? Si votre sel est découvert, n'est-ce pas compromise?
  • BenCr, seulement le code javascript s'exécutant sur mon domaine peut lire le cookie et de le mettre dans l'en-tête. Donc si il y avait un site malveillant qui a causé le navigateur pour soumettre une demande de mon site, la demande n'aurait pas l'en-tête, de sorte qu'il rejette la demande.
  • pouvez-vous expliquer quel est le résultat de la solution que vous avez décrit ici? comment est-il échouer? ou que tu nous demande de trouver des trous dans la sécurité?
  • Tout simplement à la recherche de commentaires. Il ne s'agit pas (autant que je sache)
  • pour tous les futurs utilisateurs, c'est un lien utile dans le cas où Vous travaillez avec des Asp.net MVC et AngularJs
  • peut-u s'il vous plaît montrer comment faire u utiliser ce jeton sur le côté client/angularjs.. ce code u besoin angulaire de l'utiliser??
  • il n'y a rien à faire dans Angulaire. Ce poste est sur le travail nécessaire sur le serveur de travailler avec Angulaire intégré dans XSRF comportement.
  • votre mise en œuvre semble impeccable, tout a l'air bon.
  • Deux choses: 1) pourquoi avez-vous de hachage de l'auth jeton au lieu de simplement en utilisant un jeton aléatoire généré par un CSPRNG? 2) au lieu d'utiliser un auth attribut, je suppose qu'il serait judicieux de mettre en œuvre cette délégation de gestionnaire au lieu de cela, de cette façon, vous pouvez court-circuit de la demande de façon plus tôt dans le pipeline API Web.
  • 1), nous obtenons les csrfToken de la authToken afin que nous puissions vérifier si elle est correcte quand il s'agit de nouveau sur le serveur. Si c'était juste un nombre aléatoire, nous souvenir de ce que nous avons envoyé afin que nous puissions vérifier que c'était la même quand il revint dans. 2) peut-être.
  • C'était il y a longtemps, mais j'ai remarqué que dans surchargée IsAuthorized méthode, vous n'invoque pas de base.IsAuthorized(). Parfois, il peut être utile lorsque vous traitez avec des rôles etc. Ne serait-il pas mieux comme return new CsrfTokenHelper().DoesCsrfTokenMatchAuthToken(csrfToken, authToken) && base.IsAuthorized(context); ?
  • Ainsi, la suppression des cookies en local sur le serveur avec HttpContext.Current.Response.Cookies.Remove ne pas les faire disparaître du côté client.

InformationsquelleAutor dbruning | 2013-03-22