2015-08-20 13 views
13

Nel mio MVC 5 web app ho questo (in AccountController.cs):A cosa serve XsrfKey e dovrei impostare XsrfId su qualcos'altro?

// Used for XSRF protection when adding external sign ins 
    private const string XsrfKey = "XsrfId"; 

e

 public string SocialAccountProvider { get; set; } 
     public string RedirectUri { get; set; } 
     public string UserId { get; set; } 

     public override void ExecuteResult(ControllerContext context) 
     { 
      var properties = new AuthenticationProperties { RedirectUri = RedirectUri }; 
      if (UserId != null) 
      { 
       properties.Dictionary[XsrfKey] = UserId; 
      } 

      context.HttpContext.GetOwinContext().Authentication.Challenge(properties, SocialAccountProvider); 
     } 

Come esattamente è che venga utilizzato per la protezione?

Devo impostare il valore di XsrfKey su qualcosa di più casuale?

risposta

4

Date un'occhiata a ManageController metodi LinkLogin e LinkLoginCallback:

// 
    // POST: /Manage/LinkLogin 
    [HttpPost] 
    [ValidateAntiForgeryToken] 
    public ActionResult LinkLogin(string provider) 
    { 
     // Request a redirect to the external login provider to link a login for the current user 
     return new AccountController.ChallengeResult(provider, Url.Action("LinkLoginCallback", "Manage"), User.Identity.GetUserId()); 
    } 

    // 
    // GET: /Manage/LinkLoginCallback 
    public async Task<ActionResult> LinkLoginCallback() 
    { 
     var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync(XsrfKey, User.Identity.GetUserId()); 
     if (loginInfo == null) 
     { 
      return RedirectToAction("ManageLogins", new { Message = ManageMessageId.Error }); 
     } 
     var result = await UserManager.AddLoginAsync(User.Identity.GetUserId(), loginInfo.Login); 
     return result.Succeeded ? RedirectToAction("ManageLogins") : RedirectToAction("ManageLogins", new { Message = ManageMessageId.Error }); 
    } 

Questi sono i metodi che gestiscono collegano dei conti con l'estero (cioè Google, Facebook, ecc). Il flusso va così:

  1. L'utente fa clic sul pulsante "Collega account", che chiama un metodo da POST a LinkLogin.
  2. LinkLogin restituisce ChallengeResult oggetto, con url di richiamata impostato su LinkLoginCallback metodo.
  3. ChallengeResult.ExecuteResult viene chiamato da MVC framework, chiama IAuthenticationManager.Challenge, che provoca un reindirizzamento al provider di accesso esterno specifico (diciamo: google).
  4. L'utente si autentica con google, quindi reindirizzamenti di Google a url di richiamata.
  5. Il callback viene gestito con LinkLoginCallback. Qui, vogliamo impedire XSRF e verificare che la chiamata sia stata avviata da un utente, da una pagina servita dal nostro server (e non da un sito malevolo).

Normalmente, se si trattava di una semplice sequenza di GET-POST, si dovrebbe aggiungere un nascosta <input> campo con un token anti-contraffazione e confrontarla con un corrispondente valore del cookie (che è come Asp.Net Anti-Forgery Tokens di lavoro).

Qui, la richiesta proviene da un provider di autenticazione esterno (google nel nostro esempio). Quindi dobbiamo dare il token anti-contraffazione a google e google dovrebbe includerlo nella richiesta di callback. Questo è esattamente ciò per cui è stato progettato state parameter in OAuth2.

Torniamo al nostro XsrfKey: tutto ciò che si mette in AuthenticationProperties.Dictionary verrà serializzato e inclusi nel parametro state di richiesta OAuth2 - e di conseguenza, OAuth2 callback. Ora, GetExternalLoginInfoAsync(this IAuthenticationManager manager, string xsrfKey, string expectedValue) cercherà lo XsrfKey nel dizionario di stato ricevuto e lo confronterà con lo expectedValue. Restituirà un valore ExternalLoginInfo solo se i valori sono uguali.

Quindi, rispondendo alla domanda originale: è possibile impostare XsrfKey su tutto ciò che si desidera, purché venga utilizzato lo stesso tasto durante l'impostazione e la lettura. Non ha molto senso impostarlo su qualcosa di casuale: il parametro state è crittografato, quindi nessuno si aspetta che tu possa leggerlo comunque.

+0

Grazie. Continuo a pensare che sia una buona idea cambiarlo in qualcosa di diverso dalla chiave originale che arriva in un nuovo progetto, quindi non sarà immaginabile nel caso qualcuno provasse a ricrearlo – Yovav

1

Basta lasciare così com'è:

Come il nome degli Stati membri è una chiave:

private const string XsrfKey = "XsrfId"; 

Essa è definita in questo modo per evitare di "numeri magici" e quindi viene utilizzato un po 'giù nel codice patibolo:

public override void ExecuteResult(ControllerContext context) 
{ 
    var properties = new AuthenticationProperties { RedirectUri = RedirectUri }; 
    if (UserId != null) 
    { 
     properties.Dictionary[XsrfKey] = UserId; 
    } 
    context.HttpContext.GetOwinContext().Authentication.Challenge(properties, LoginProvider); 
} 

il valore della voce di dizionario è quindi impostata la proprietà UserId nel codice sopra utilizzando il membro XsrfKey come la chiave.

IOW il codice sta già impostando la voce del dizionario XSRF sul valore dell'ID utente nello snippet. Se si modifica il valore dei membri XsrfKey in qualsiasi altra cosa, si verificheranno problemi lungo la linea, poiché la chiave prevista "XsrfId" non avrà alcun valore impostato.

Se cambiandolo in qualcosa di più casuale si sta implicando di modificare il valore e non la chiave del dizionario, o in altre parole, non impostarlo sull'id utente, quindi vedere quanto segue per una spiegazione dell'ant falsi simboli interni.

http://www.asp.net/mvc/overview/security/xsrfcsrf-prevention-in-aspnet-mvc-and-web-pages