2016-03-29 68 views
11

Ho un'app Angular2. È in esecuzione all'interno di ASP.NET 5 (Core).
Effettua chiamate Http al controller che funziona correttamente.Angular2 ASP.NET Core AntiForgeryToken

Ma ora ho bisogno di stabilire la proiezione Cross Site Scripting.

Come si genera un nuovo token su ogni richiesta HTTP e successivamente si esegue il controllo AntiForgeryToken nelle app Angular2?

Nota: i miei moduli dati in Angular non vengono prodotti da una visualizzazione MVC ma interamente scritti in Angular2 e solo i servizi Web di chiamata.

Tutti gli esempi che ho visto sono obsoleti e non funzionano/non funzionano completamente.

Come integrare i controlli AntiForgeryToken in Angular2 rispetto a ASP.NET 5 in cui i moduli sono puramente angolari?

Grazie.

risposta

6

Un filtro di azione personalizzato non è necessario. Può essere tutto cablato in 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); 
    }); 

    (...) 
} 

Poi tutto ciò che serve nel vostro controller è la [ValidateAntiForgeryToken] decoratore ovunque si desidera imporre che un token è fornito.

Per riferimento, ho trovato questa soluzione qui - AspNet AntiForgery Github Issue 29.

+0

Ho seguito i passaggi precedenti ma ricevo 400 errori di richiesta errati. La mia richiesta "post" va al server come "opzioni: tipo di metodo." Ho posto una domanda su questo problema- https://stackoverflow.com/questions/44841588/antiforgery-token-implementation-in-angular-2-and- web-api-using-aps-net-core –

+0

Alcune informazioni aggiuntive che ho scoperto oggi: se stai ospitando in IIS, devi configurare Data Protection sul server per mantenere le chiavi utilizzate per generare AntiForgeryToken. , i token non saranno più validi al riavvio dell'app. Vedi qui per informazioni su come configurare - https://docs.microsoft.com/en-us/aspnet/core/publishing/iis#data-protection – DanO

0

Penso che sia necessario creare un attributo personalizzato AntiForgeryValidationToken che supporti l'invio di token tramite intestazione anziché valori di modulo. Quindi aggiungi token all'intestazione di ogni richiesta dalla tua app Angular2 alla tua API. Esempio qui How do you set global custom headers in Angular2?

0

Per convalidare il token da un colpo di testa si può usare qualcosa di simile:

[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"]); 
     } 
    } 

Poi basta aggiungere [ValidateHeaderAntiForgeryToken] sui metodi di controller. Nota, si tratta di un progetto MVC 5, ASP.NET 4.5.2, quindi potrebbe essere necessario modificarlo leggermente per adattarsi a .NET Core. Inoltre ho modificato questo per restituire un risultato JSON se il token è mancante, è possibile rimuovere quella parte se non si gestisce la risposta all'errore e l'output all'utente. Crediti per la parte fondamentale di questo attributo va a: https://nozzlegear.com/blog/send-and-validate-an-asp-net-antiforgerytoken-as-a-request-header

La parte difficile è come generare l'AntiForgeryToken senza utilizzare @Html.AntiForgeryToken() in puro 2 applicazione angolare (senza accesso a .cshtml file). Sto cercando una risposta anche a questo.

+0

Mi chiedo se hai mai trovato una risposta a come creare il token senza utilizzare @ Html.AntiForgeryToken()? – Jeremy

2

Sto utilizzando un filtro azione per inviare i token di richiesta. Basta applicarlo alle azioni che desideri un nuovo token antiforgery, ad es. Angular2 SPA, l'azione WebAPI, ecc

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

Registrati l'attributo di avvio e configurare Antiforgery servizio per leggere la richiesta sotto forma di token header "X-XSRF-TOKEN".

public class Startup 
{ 
    // ... 

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

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

Qualche suggerimento su come utilizzare questo approccio in una SPA? Le azioni GET non vengono mai colpite (tranne/Home/Indice), come si consegna un nuovo gettone per ogni modulo che eseguirà un POST più tardi? –

+1

Provare ad applicare AngularAntiForgeryTokenAttribute agli endpoint POST. Dovresti essere in grado di rinnovare il token nelle azioni POST. – fszlin