web-dev-qa-db-fra.com

Angular2 ASP.NET Core AntiForgeryToken

J'ai un Angular2 app. Il est exécuté dans ASP.NET 5 (Core) .
Il effectue des appels HTTP vers le contrôleur, qui fonctionne correctement.

Mais maintenant, je dois établir une projection Cross Site Scripting.

Comment générer un nouveau jeton sur chaque requête HTTP, puis effectuer ensuite la vérification AntiForgeryToken dans les applications Angular2?  

Remarque: Mes formulaires de données dans Angular ne sont pas générés à partir d'une vue MVC mais entièrement écrits dans Angular2 et appellent uniquement des services Web.

Tous les exemples que j'ai vus sont périmés et ne fonctionnent pas/ne fonctionnent pas complètement.

Comment intégrer les contrôles AntiForgeryToken dans Angular2 contre ASP.NET 5 où les formulaires sont purement angulaires?

Merci.

14
DanAbdn

Un filtre d'action personnalisé n'est pas nécessaire. Tout peut être câblé dans Startup.cs.

using Microsoft.AspNetCore.Antiforgery;

(...)

public void ConfigureServices(IServiceCollection services)
{
  services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");

  (...)
}

public void Configure(IApplicationBuilder app, IAntiforgery antiforgery)
{
  app.Use(next => context =>
  {
    if (context.Request.Path == "/")
    {
      //send the request token as a JavaScript-readable cookie, and Angular will use it by default
      var tokens = antiforgery.GetAndStoreTokens(context);
      context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken, new CookieOptions { HttpOnly = false });
    }
    return next(context);
  });

  (...)
}

Ensuite, tout ce dont vous avez besoin dans vos contrôleurs est le décorateur [ValidateAntiForgeryToken], quel que soit l'endroit où vous souhaitez appliquer un jeton.

Pour référence, j'ai trouvé cette solution ici - AspNet AntiForgery Github Issue 29 .

6
DanO

J'utilise un filtre d'action pour envoyer les jetons de requête. Appliquez-le simplement aux actions pour lesquelles vous souhaitez un nouveau jeton antiforgery, par exemple. SPA angulaire2, action WebAPI, etc.

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public class AngularAntiForgeryTokenAttribute : ActionFilterAttribute
{
    private const string CookieName = "XSRF-TOKEN";
    private readonly IAntiforgery antiforgery;

    public AngularAntiForgeryTokenAttribute(IAntiforgery antiforgery)
    {
        this.antiforgery = antiforgery;
    }

    public override void OnResultExecuting(ResultExecutingContext context)
    {
        base.OnResultExecuting(context);

        if (!context.Cancel)
        {
            var tokens = antiforgery.GetAndStoreTokens(context.HttpContext);

            context.HttpContext.Response.Cookies.Append(
                CookieName,
                tokens.RequestToken,
                new CookieOptions { HttpOnly = false });
        }
    }
}
/* HomeController */

[ServiceFilter(typeof(AngularAntiForgeryTokenAttribute), IsReusable = true)]
public IActionResult Index()
{
    return View();
}

/* AccountController */

[HttpPost()]
[AllowAnonymous]
[ValidateAntiForgeryToken]
// Send new antiforgery token
[ServiceFilter(typeof(AngularAntiForgeryTokenAttribute), IsReusable = true)]
public async Task<IActionResult> Register([FromBody] RegisterViewModel model)
{
    //...
    return Json(new { }); 
}

Enregistrez l'attribut dans Démarrage et configurez le service Antiforgery pour qu'il lise l'en-tête de jeton de requête "X-XSRF-TOKEN".

public class Startup
{
    // ...

    public void ConfigureServices(IServiceCollection services)
    {
        // ...

        services.AddScoped<AngularAntiForgeryTokenAttribute>();
        services.AddAntiforgery(options =>
        {
            options.HeaderName = "X-XSRF-TOKEN";
        });
    }
}
3
fszlin

Je pense que vous devez créer un attribut AntiForgeryValidationToken personnalisé qui prend en charge l'envoi de jeton via un en-tête plutôt que des valeurs de formulaire. Ajoutez ensuite un jeton à l'en-tête de chaque demande de votre application Angular2 vers votre api. Exemple ici Comment définissez-vous les en-têtes globaux personnalisés dans Angular2?

0
Wanton

Pour valider le jeton depuis un en-tête, vous pouvez utiliser quelque chose comme ceci:

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
    public sealed class ValidateHeaderAntiForgeryTokenAttribute : FilterAttribute, IAuthorizationFilter
    {
        public void OnAuthorization(AuthorizationContext filterContext)
        {
            if (filterContext == null)
            {
                throw new ArgumentNullException(nameof(filterContext));
            }

            var httpContext = filterContext.HttpContext;
            if (httpContext.Request.Headers["__RequestVerificationToken"] == null)
            {
                httpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
                httpContext.Response.StatusDescription = "RequestVerificationToken missing.";

                filterContext.Result = new JsonResult
                {
                    Data = new { ErrorMessage = httpContext.Response.StatusDescription },
                    JsonRequestBehavior = JsonRequestBehavior.AllowGet
                };
                return;
            }
            var cookie = httpContext.Request.Cookies[System.Web.Helpers.AntiForgeryConfig.CookieName];
            System.Web.Helpers.AntiForgery.Validate(cookie != null ? cookie.Value : null, httpContext.Request.Headers["__RequestVerificationToken"]);
        }
    }

Ensuite, vous ajoutez simplement [ValidateHeaderAntiForgeryToken] aux méthodes de votre contrôleur. Notez cependant qu'il s'agit d'un projet ASP.NET 4.5.2 de MVC 5; vous devrez donc peut-être le modifier légèrement pour vous adapter à .NET Core. De plus, j’ai modifié cela pour renvoyer un résultat JSON si le jeton est manquant. Vous pouvez supprimer cette partie si vous ne gérez pas la réponse à l’erreur et ne la restituez pas à l’utilisateur. à: https://nozzlegear.com/blog/send-and-validate-an-asp-net-antiforgerytoken-as-a-request-header

Le plus difficile est de savoir comment générer AntiForgeryToken sans utiliser @Html.AntiForgeryToken() dans une application pure Angular 2 (sans accès aux fichiers .cshtml). Je cherche une réponse à cela aussi.

0
hug