Evitare attacchi basati su tampering dei dati in ASP.NET MVC

di Marco De Sanctis, in ASP.NET MVC, C#,

Quando in ASP.NET MVC realizziamo una action per gestire il post di una form, ad esempio per modificare una entità Person su database, possiamo scrivere un metodo il cui argomento è il vero e proprio model, che il framework provvede a popolare in base ai dati pervenuti dal browser.

C#
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(Person person)
{
    // qui salvataggio su DB

    return this.RedirectToAction("Index");
}

Si tratta di una funzionalità molto comoda, perché ci consente di ragionare a oggetti e di lavorare quindi ad un alto livello di astrazione: ciò che accade dietro alle quinte è che ASP.NET MVC associa i dati ricevuti dal post alle relativa proprietà basandosi sul nome del campo nella form. Eppure un'implementazione della action di Edit come quella precedente nasconde in realtà una pericolosa falla di sicurezza.

Immaginiamo infatti che Person abbia una proprietà Role che non vogliamo rendere accessibile all'utente, tanto da farci decidere, ad esempio, di non includere alcun editor per questo dato nelle view di creazione o di modifica. In queste condizioni, però, un hacker potrebbe modificare il contenuto del form postato (tampering dei dati), includendo artificiosamente un campo di nome Role; ASP.NET MVC avrebbe tutte le ragioni per ritenere perfettamente valido anche questo dato, aggiornando di fatto la relativa proprietà dell'oggetto sul server!

Si tratta di problema potenzialmente serio, che però possiamo evitare in vari modi. Se utilizziamo i metodi UpdateModel o TryUpdateModel per aggiornare il model, è possibile specificare una whitelist con l'elenco delle sole proprietà che si vogliono valorizzare:

C#
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(Person person)
{
    var p = new Person();

    // non aggiorniamo Role, anche se inviato in POST
    this.UpdateModel(p, new string[] { "FirstName", "LastName"});

    // qui salvataggio su DB

    return this.RedirectToAction("Index");
}

Il medesimo elenco può essere utilizzato per gestire la creazione, tramite l'attributo Bind e la proprietà Include; in questo modo le proprietà del model non presenti in whitelist non verranno valorizzate:

C#
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(
  [Bind(Include = "FirstName, LastName")]Person person)
{
    // qui salvataggio su DB

    return this.RedirectToAction("Index");
}

Entrambi questi metodi prevedono, eventualmente, anche la possibilità di fornire una blacklist, ossia un elenco di proprietà il cui aggiornamento è vietato. Attenzione al fatto che l'attributo Bind utilizzato come nell'esempio precedente, viene ignorato da UpdateModel/TryUpdateModel. Questo limite non sussiste nel caso in cui sia applicato direttamente sul model:

C#
[Bind(Include = "FirstName, LastName")]
public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Role { get; set; }
}

Commenti

Visualizza/aggiungi commenti

| Condividi su: Twitter, Facebook, LinkedIn

Per inserire un commento, devi avere un account.

Fai il login e torna a questa pagina, oppure registrati alla nostra community.

Approfondimenti

I più letti di oggi