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.
Vous devez vous connecter pour publier un commentaire.
Votre code semble aller pour le mieux. La seule chose est, vous n'avez pas besoin de plus de code que vous avez en tant que web.l'api fonctionne "au dessus" de asp.net mvc, et ce dernier a un support intégré pour la lutte anti-contrefaçon jetons.
Dans les commentaires dbrunning et ccorrin exprimer les préoccupations que vous ne pourrez utiliser à construire dans AntiForgery jetons uniquement lorsque vous utilisez le MVC, html helpers. Il n'est pas vrai. Les accompagnateurs peuvent simplement exposer session paire de jetons que vous pouvez valider les uns contre les autres. Voir ci-dessous pour plus de détails.
Mise à JOUR:
Il existe deux méthodes que vous pouvez utiliser à partir de AntiForgery:
AntiForgery.GetTokens
utilise deux paramètres pour revenir cookie jeton et la forme de jeton deAntiForgery.Validate(cookieToken, formToken)
valide si la paire de jetons est valableVous pouvez réutiliser ces deux méthodes et de l'utilisation formToken comme headerToken et cookieToken réels cookieToken. Puis il suffit d'appeler valider, tant à l'intérieur de l'attribut.
Une autre solution est d'utiliser JWT (vérifier par exemple MembershipReboot mise en œuvre)
Ce lien montre comment utiliser intégré dans la lutte anti-contrefaçon jetons avec ajax:
Aussi jeter un oeil à cette question AngularJS ne pouvez pas trouver XSRF-JETON de cookie
Je pense que ton code est erroné. L'idée autour de prévenir CSRF est d'empêcher un jeton unique pour chaque REQUÊTE, et non pas de chaque session. Si l'anti-contrefaçon de marque est une session persisté valeur, la capacité à effectuer des CSRF reste. Vous devez fournir un jeton unique sur chaque demande...
Cette solution n'est pas sécurisé car les attaques de type CSRF sont encore possible tant que l'Auth cookie est valide. À la fois l'authentification et la xsrf cookie sera envoyé au serveur quand un attaquant fait d'effectuer une demande via un autre site, et donc, vous êtes toujours vulnérable jusqu'à ce que l'utilisateur fait un "dur" déconnexion.
Chaque demande ou de la session doit avoir son propre jeton d'empêcher véritablement FSCC attaques. Mais probablement la meilleure solution est de ne pas utiliser un cookie d'authentification basée sur mais de jeton d'authentification basée sur comme OAuth. Cela empêche d'autres sites web à l'aide de vos cookies à réaliser indésirables demandes, depuis les jetons sont utilisés dans les entêtes http au lieu de cookies. Et les en-têtes http ne sont pas automatiquement envoyer.
Ces excellents posts de blog contiennent des informations de la façon de mettre en œuvre le protocole OAuth pour WebAPI. Le blog contient également de la grande information de la manière de l'intégrer avec AngularJS.
Une autre solution serait de désactiver la SCRO et seulement accepter les demandes de liste blanche des domaines. Cependant cela ne fonctionne pas pour les non-site web demandes, tels que mobile et/ou de postes clients. Côté une fois que votre site web est vulnérable à une attaque XSS l'attaquant va encore être en mesure de forger des requêtes sur votre behalve.
N'ai pas eu de problèmes a souligné avec le code, donc je considère que la réponse à la question.