Il presente articolo è stato tradotto automaticamente.

Sicurezza ASP.NET

Sicurezza delle applicazioni ASP.NET

Adam Tuliper

Nel numero precedente, ho discusso l'importanza di costruire la sicurezza nelle applicazioni Web e guardato alcuni tipi di attacchi, tra cui SQL injection e parametro manomissione e come prevenirli (msdn.microsoft.com/magazine/hh580736). In questo articolo, un tuffo in due attacchi più comuni per aiutare turno fuori il nostro arsenale delle protezioni di applicazione — cross-site scripting (XSS) e cross-site request forgery (CSRF).

Potreste domandarti: Perché non basta usare uno scanner di sicurezza di produzione? Scanner sono grandi strumenti per la ricerca di frutta a basso impiccagione e sono particolarmente bene a trovare applicazione e sistema problemi di configurazione, ma non sanno l'applicazione il modo di che fare. Pertanto, è indispensabile che si familiarizzano con potenziali problemi di sicurezza e prendere il tempo per controllare le vostre applicazioni e costruire la sicurezza nel vostro ciclo di sviluppo del software.

Cross-Site Scripting

**Cos'è?**XSS è un attacco in cui script malignamente viene iniettato nella sessione di navigazione di un utente, generalmente a insaputa dell'utente. Questi tipi di attacchi sono diventati abbastanza familiari a molte persone a causa di incidenti in cui è stato colpito un grande sito di social networking e suoi utenti avevano inviati messaggi di essi non autorizzare. Se un utente malintenzionato post script dannoso che egli può causare il browser eseguire, questo script viene eseguito nel contesto della sessione della vittima, che essenzialmente permette all'attaccante di fare qualsiasi cosa che vuole al DOM — tra cui mostrando le finestre di dialogo di accesso falso o rubare i cookie. Un tale attacco potrebbe anche installare un registratore di tasti HTML della pagina corrente per inviare continuamente ingresso da quella finestra a un sito remoto.

**Come le è sfruttata?**XSS è sfruttata tramite diversi metodi, che si basano su avendo unescaped o impropriamente fuggiti output. Prendiamo il caso di un'applicazione che ha bisogno per visualizzare un messaggio di stato semplice per l'utente finale. In genere questo messaggio è passato sulla stringa di query, come illustrato nella Figura 1.

Query String Message
Figura 1 messaggio di Query String

Questa tecnica è comunemente utilizzata dopo un redirect a mostrare all'utente una sorta di status, come ad esempio il messaggio profilo salvato in Figura 1. Il messaggio viene letto dalla stringa di query e scritto destra fuori alla pagina. Se l'output non è codificata in formato HTML, chiunque può facilmente iniettare JavaScript al posto del messaggio di stato. Questo tipo di attacco è considerato un attacco XSS riflesso, perché tutto ciò che è la stringa di query ottiene resi terzino destro alla pagina. In un attacco persistente script dannoso viene memorizzato, solitamente in un database o un biscotto.

In Figura 1 si può vedere questo URI accetta un parametro msg. La pagina Web per questo URI conterrebbe codice come il seguente semplicemente scrivere la variabile alla pagina con alcuna codifica:

    <div class="messages"> <%=Request.QueryString["msg"]%></div>

Se si sostituisce "Profilo salvato" con lo script mostrato in Figura 2, la funzione di allarme pop-up nel browser dallo script incluso nella stringa di query. La chiave per l'exploit qui è che i risultati non sono codificati in HTML e quindi il <script> Tag è effettivamente analizzati come JavaScript valida dal browser e giustiziato. Questo è chiaramente non quanto lo sviluppatore qui aveva in mente.

Injecting Script into the URI
Figura 2 iniettare Script l'URI

Così si apre un avviso — Qual è il grosso problema? Diamo un po' di più, come mostrato in questo esempio Figura 3. Si noti che io ho accorciato l'attacco qui per fare il punto; Questa sintassi non è esattamente corretta ma una lieve modifica sarebbe trasformare questo in un vero e proprio attacco.

Creating a Malicious Attack
Figura 3 creazione di un attacco distruttivo

Un attacco come questo causerebbe un dialogo login falso di essere mostrati agli utenti, dove su di essi sarebbe allegramente inserire le proprie credenziali. In questo caso, viene scaricato un script remoto, che generalmente è consentito dalle impostazioni di sicurezza del browser predefinito. Questo tipo di attacco può in teoria accadere dovunque una stringa che non è stata codificata o sterilizzata può essere eco torna a un utente.

Figura 4 mostra un attacco utilizzando script simili su un sito di sviluppo che consente agli utenti di lasciare commenti sui suoi prodotti. Invece di lasciare una recensione del prodotto reale, tuttavia, qualcuno entrò JavaScript dannosi come un commento. Questo script ora viene visualizzata una finestra di login per ogni singolo utente, raggiungendo la pagina Web e raccoglie e trasmette le credenziali per un sito remoto. Questo è un attacco XSS persistente; lo script è memorizzato nel database e ripetuto per chiunque visiti la pagina.

A Persistent XSS Attack Showing a Fake Dialog
Figura 4 persistente XSS Attack visualizzando una finestra di dialogo Fake

Un altro modo è sfruttata XSS è utilizzando gli elementi HTML, come quando il testo dinamico è consentito nel tag HTML, in questo modo:

    <img onmouseover=alert([user supplied text])>

Se un utente malintenzionato inietta il testo come "onmouseout = avviso (docu­ment.cookie)," questo crea il seguente tag nel browser che accede il cookie:

    <img onmouseover=alert(1) onmouseout=alert(document.cookie) >

Non non c'è nessun tag "<script>" per filtrare potenzialmente input sul e niente di fuggire, ma questo è un pezzo completamente valido di JavaScript che può leggere un cookie — potenzialmente un cookie di autenticazione. Ci sono modi di specifico per rendere questo più sicuri, ma a causa del rischio, è meglio non permettono di raggiungere questo codice inline qui qualsiasi input dell'utente.

**Come impedire XSS?**Seguendo queste regole strettamente contribuirà a prevenire più, se non tutti XSS attacchi nell'applicazione:

  1. Assicurarsi che tutto il vostro output è codificata in formato HTML.

  2. Non permettono il testo fornito dall'utente a finire in qualsiasi stringa di attributo di elemento HTML.

  3. Impedire l'utilizzo di Internet Explorer 6 dall'applicazione controllando Request.Browser come descritto in msdn.microsoft.com/library/3yekbd5b.

  4. Conoscere il comportamento del controllo e se esso codifica HTML per l'output. Se non è così, codificare i dati andando al controllo.

  5. Utilizzare il Microsoft Anti-Cross Site Scripting Library (AntiXSS) e impostarlo come tuo codificatore HTML predefinita.

  6. Utilizzare l'oggetto AntiXSS Sanitizer (questa libreria è un download separato ed è affrontata più avanti in questo articolo) per chiamare GetSafeHtml o GetSafeHtmlFragment prima del salvataggio dei dati HTML nel database; non codificare i dati prima di salvare.

  7. Per i moduli Web, non impostare EnableRequestValidation = false nelle tue pagine Web. Purtroppo, la maggior parte delle registrazioni di gruppo utente sul Web consigliano la disattivazione di questa impostazione se c'è un errore. L'impostazione è lì per un motivo e si fermerà la richiesta, se la combinazione di caratteri "< X," ad esempio, viene inviato al server. Se i controlli sono distacco HTML al server e ricevendo l'errore mostrato in Figura 5, idealmente si deve codificare i dati prima di postare al server. Questo è uno scenario comune con controlli WYSIWYG, e più moderne versioni codificherà correttamente i loro dati HTML prima di postare al server.

    Server Error from Unencoded HTML
    Figura 5 Server Error da HTML non codificata

  8. Per le applicazioni ASP.NET MVC 3 applicazioni, quando è necessario pubblicare HTML al tuo modello, non utilizzano ValidateInput(false) per disattivare la convalida richiesta. [AllowHtml] è sufficiente aggiungere alla tua proprietà del modello, in questo modo:

public class BlogEntry
{
  public int UserId {get;set;}
  [AllowHtml]
  public string BlogText {get;set;}
}

Alcuni prodotti tentano di rilevare <script> e altre combinazioni di parole o modelli di espressione regolare in una stringa per cercare di individuare XSS. Questi prodotti possono fornire ulteriori controlli, ma non sono completamente affidabili a causa delle molte varianti gli aggressori hanno creato. Prendere un'occhiata la XSS "Cheat Sheet" a ha.ckers.org/xss.html per vedere quanto sia difficile rilevamento può essere.

Per comprendere le correzioni, supponiamo che un utente malintenzionato ha iniettato qualche script che finì in una variabile nella nostra applicazione dalla stringa di query o un campo di modulo, come illustrato di seguito:

string message = Request.QueryString["msg"];

o:

string message = txtMessage.Text;

Si noti che anche se un controllo TextBox HTML consente di codificare l'output, esso non codifica la proprietà Text quando si leggerla in dal codice. Con una di queste righe di codice, sei lasciato con la seguente stringa nella variabile di messaggio:

message = "<script>alert('bip')</script>"

In una pagina Web contenente codice simile al seguente, il JavaScript verrà eseguito nel browser dell'utente semplicemente perché questo testo è stato scritto per la pagina:

    <%=message %>

Codifica l'output HTML si ferma questo attacco in sue tracce. Figura6 mostra le principali opzioni per la codifica dei dati pericolosi.

Queste opzioni impediscono il tipo di attacco illustrato nell'esempio e devono essere utilizzate nelle applicazioni.

Nella figura 6 opzioni di codifica in formato HTML

ASP.NET (entrambi MVC o Web Form) < % %=Server.HtmlEncode(message) >
Moduli Web (ASP.NET 4 sintassi) <%: messaggio % >
ASP.NET MVC 3 Razor @ messaggio
Associazione dati

Purtroppo, la sintassi di associazione dati ancora non contiene una sintassi di codifica integrata; è venuta nella prossima versione di ASP.NET come < % #: %>. Fino ad allora, utilizzare:

< % # Server.HtmlEncode(Eval("PropertyName")) % >

Meglio codifica

Dalla libreria AntiXSS nello spazio dei nomi Microsoft.Security.Application:

Encoder.HtmlEncode(Message)

È importante conoscere i controlli. Quali controlli HTML codificano i vostri dati per voi e non che controlla? Ad esempio, un controllo TextBox esegue la codifica HTML l'output di rendering, ma non un LiteralControl. Questa è una distinzione importante. Un controllo textbox assegnate:

yourTextBoxControl.Text = "Test <script>alert('bip')</script>";

correttamente il rendering del testo alla pagina come:

    Test &lt;script&gt;alert(&#39;bip&#39;)&lt;/script&gt;

Al contrario:

yourLiteralControl.Text = "Test <script>alert('bip')</script>";

provoca un avviso di JavaScript per essere visualizzato nella pagina, confermando la vulnerabilità XSS. La correzione qui è semplicemente:

yourLiteralControl.Text = Server.HtmlEncode(
    "Test <script>alert('bip')</script>");

Questo è un po' più complicato quando si utilizza l'associazione dati in Web Form. Guarda l'esempio seguente:

    <asp:Repeater ID="Repeater1" runat="server">
        <ItemTemplate>
          <asp:TextBox ID="txtYourField" Text='<%# Bind("YourField") %>'
            runat="server"></asp:TextBox>
        </ItemTemplate>
      </asp:Repeater>

È questo vulnerabile? No, non è. Anche se il codice inline sembra come se potrebbe scrivere fuori lo script o uscire dalle quotazioni di controllo, infatti è codificato.

Che dire di questo:

    <asp:Repeater ID="Repeater2" runat="server">
      <ItemTemplate>
        <%# Eval("YourField") %>
      </ItemTemplate>
    </asp:Repeater>

È vulnerabile? Sì lo è. La sintassi di associazione dati < % # % > non codifica HTML. Ecco la correzione:

    <asp:Repeater ID="Repeater2" runat="server">
      <ItemTemplate>
        <%#Server.HtmlEncode((string)Eval("YourText"))%>
      </ItemTemplate>
    </asp:Repeater>

Tenere presente che se si utilizza Bind in questo scenario non è possibile avvolgere un server. HtmlEncode intorno ad esso, a causa di come impegnare compila dietro le quinte come due chiamate separate. Questo avrà esito negativo:

    <asp:Repeater ID="Repeater2" runat="server">
      <ItemTemplate>
        <%#Server.HtmlEncode((string)Bind("YourText"))%>
      </ItemTemplate>
    </asp:Repeater>

Se si utilizza Bind e non è assegnando il testo a un controllo che consente di codificare HTML (ad esempio il controllo TextBox), considerare l'utilizzo di Eval invece così si può avvolgere la chiamata al server. HtmlEncode, come nell'esempio precedente.

Lo stesso concetto di associazione dati non esiste in ASP.NET MVC, quindi avrai bisogno di sapere se gli helper HTML codificherà. Gli helper per etichette e caselle di testo do HTML codificano. Ad esempio, questo codice:

@Html.TextBox("customerName", "<script>alert('bip')</script>")
@Html.Label("<script>alert('bip')</script>")

esegue il rendering come:

    <input id="customerName" name="customerName" type="text"
      value="&lt;script>alert(&#39;bip&#39;)&lt;/script>" />
    <label for="">&lt;script&gt;alert(&#39;bip&#39;)&lt;/script&gt;</label>

Accennato in precedenza il AntiXSS. Attualmente alla versione 4.1 beta 1, la libreria di AntiXSS ha attraversato una riscrittura molto bella e, per quanto riguarda la sicurezza, fornisce un codificatore HTML migliore di quello che viene fornito con ASP.NET. Non è che non c'è nulla di sbagliato con server. HtmlEncode, ma il suo focus è la compatibilità, non di sicurezza. AntiXSS utilizza un approccio differente per codificare. Potete leggere di più su di esso a msdn.microsoft.com/security/aa973814.

La versione beta è disponibile presso bit.ly/gMcB5K. Controllare per vedere se AntiXSS essere fuori da beta ancora. In caso contrario, sarà necessario scaricare il codice e compilarlo. Jon Galloway ha un ottimo post su questo a bit.ly/lGpKWX.

Per utilizzare il codificatore di AntiXSS, è possibile semplicemente rendere la chiamata seguente:

    <%@ Import Namespace="Microsoft.Security.Application" %>
    ...
    ...
    <%= Encoder.HtmlEncode(plainText)%>

ASP.NET MVC 4 aggiunto una grande nuova funzionalità che consente di ignorare il codificatore di ASP HTML predefinita e utilizzare il codificatore di AntiXSS al suo posto. Redazione di questo, è necessaria la versione 4.1; perché è attualmente in versione beta, è necessario scaricare il codice, compilarlo e aggiungere la libreria come riferimento all'applicazione — che prende tutti i cinque minuti. Poi, nel Web. config, aggiungere la seguente riga in <system.web> sezione:

<httpRuntime encoderType=
  "Microsoft.Security.Application.AntiXssEncoder, AntiXssLibrary"/>

Ora, qualsiasi chiamata codifica HTML effettuata tramite qualsiasi di sintassi elencate in Figura 6, tra cui ASP.Sintassi di NET MVC 3 rasoio, sarà ottenere codificato dalla libreria AntiXSS. Come è che per una caratteristica pluggable?

Questa biblioteca include anche un oggetto di disinfettante che può essere utilizzato per purificare HTML prima di riporlo in un database, che è molto utile se si fornisce un editor WYSIWYG per l'utente per la modifica HTML. Questa chiamata tenta di rimuovere script dalla stringa:

using Microsoft.Security.Application;
...
...
string wysiwygData = "before <script>alert('bip ')</script> after ";
string cleanData = Sanitizer.GetSafeHtmlFragment(wysiwygData);
This results in the following cleaned string that can then be saved to the database:
cleanData = "before  after ";

Cross-Site Request Forgery (CSRF)

**Cos'è?**Cross-site request forgery o CSRF (pronunciato mare-surf), è un attacco che si verifica quando qualcuno sfrutta il trust tra il browser e un sito Web per eseguire un comando utilizzando la sessione dell'utente innocente. Questo attacco è un po' più difficile immaginare senza vedere i dettagli, quindi cerchiamo di ottenere diritto ad esso.

**Come le è sfruttata?**Supponiamo che John è stato autenticato come un admin­istrator sul sito PureShoppingHeaven. PureShoppingHeaven ha un URL che è limitato all'accesso admin e permette di informazioni da passare sull'URL per eseguire un'azione, ad esempio la creazione di un nuovo utente, come illustrato nella Figura 7.

Passing Information on the URL
Figura 7 passando informazioni sull'URL

Se un utente malintenzionato può ottenere John per richiedere questo URL tramite qualsiasi di una varietà di metodi, suo browser verrà richiesta dal server e inviare su qualunque informazioni di autenticazione potrebbero già essere memorizzato nella cache o in uso nel browser di John, quali cookie di autenticazione o altri token di autenticazione, tra cui l'autenticazione di Windows.

Questo è un esempio semplice, ma gli attacchi CSRF possono essere molto più sofisticati e possono incorporare forma POSTs in aggiunta per ottenere le richieste e può trarre vantaggio da altri attacchi come XSS allo stesso tempo.

Supponiamo che John visite un vulnerabile sito di social networking che è stato sfruttato. Forse un utente malintenzionato ha messo un po' di JavaScript nella pagina tramite una vulnerabilità XSS che ora le richieste URL sotto sessione di John AddUser.aspx. Questa discarica da Fiddler (fiddler2.com) dopo che John visita la pagina Web mostra anche i browser è l'invio attraverso un cookie di autenticazione sito personalizzato:

GET http://pureshoppingheaven/AddUser.aspx?userName=hacked&pwd=secret HTTP/1.1
Host: pureshoppingheaven
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)
Cookie: CUSTOMERAUTHCOOKIE=a465bc0b-e1e2-4052-8292-484d884229ab

Tutto ciò accade senza John saperlo. È importante capire che da design il browser invierà su qualsiasi cookie validi o informazioni di autenticazione. Avete mai notato che tuo client di posta elettronica in generale non caricare immagini di default? Uno dei motivi è di prevenire CSRF. Se hai ricevuto una posta elettronica in formato HTML con un tag di immagine incorporata come la seguente, che potrebbe essere richiesto l'URL e il server avrebbe eseguito quell'azione, se sei autenticato a quel sito Web:

    <img src='yoursite/createuser.aspx?id=hacked&pwd=hacked' />

Se ti è capitato di essere un admin su "tuosito", che è già autenticato, il browser avrebbe felicemente inviare su tale richiesta GET con qualsiasi credenziali. Il server vede questo come una valida richiesta da un utente autenticato e lo avvia la richiesta senza di te mai sapere, perché non non c'è alcuna risposta di immagine valido per eseguire il rendering nel vostro client di posta elettronica.

**Come prevenire CSRF?**Per evitare CSRF, cominciate seguendo alcune regole:

  1. Assicurare che una richiesta non può essere riprodotti semplicemente cliccando su un link per una richiesta GET. Le specifiche HTTP per le richieste GET implica richieste GET devono essere utilizzate solo per il recupero, non modifica di stato.
  2. Assicurare che una richiesta non può essere riprodotti se un utente malintenzionato ha utilizzato JavaScript per imitare una richiesta POST di forma.
  3. Prevenire eventuali azioni tramite GET. Ad esempio, non consentono il record di essere creato o eliminato tramite un URL. Idealmente, questi dovrebbero richiedere qualche interazione dell'utente. Mentre questo non impedisce un attacco più intelligente basata su form, limita una serie di attacchi più facile, come il tipo descritto in esempio di immagine di posta elettronica, nonché base link incorporati nei siti XSS compromessa.

Come evitare attacchi via Web Form viene gestito un po' diversamente da ASP.NET MVC. Con Web Form, l'attributo ViewState MAC può essere firmato, che aiuta a protegge contro la contraffazione, finché non si imposta EnableViewStateMac = false. Anche voi volete firmare il ViewState con la sessione utente corrente e impedire il ViewState, essendo passati sulla stringa di query per bloccare ciò che alcuni si riferiscono a come un attacco di un clic (vedere Figura 8).

Figura 8 prevenire un attacco di un solo clic

void Page_Init(object sender, EventArgs e)
{
  if (Session.IsNewSession)
  {
    // Force session to be created;
    // otherwise the session ID changes on every request.
    Session["ForceSession"] = DateTime.Now;
  }
  // 'Sign' the viewstate with the current session.
  this.ViewStateUserKey = Session.SessionID;
  if (Page.EnableViewState)
  {
    // Make sure ViewState wasn't passed on the querystring.
    // This helps prevent one-click attacks.
    if (!string.IsNullOrEmpty(Request.Params["__VIEWSTATE"]) &&
      string.IsNullOrEmpty(Request.Form["__VIEWSTATE"]))
    {
      throw new Exception("Viewstate existed, but not on the form.");
    }
  }
}

La ragione di che assegnare un valore casuale sessione qui è per assicurarsi che la sessione è stabilita. È possibile utilizzare qualsiasi identificatore di sessione temporanea, ma l'ASP.NET session ID cambierà ad ogni singola richiesta fino a creare effettivamente una sessione. Si può avere l'ID di sessione cambiando con ogni richiesta qui, quindi dovete fissare creando la nuova sessione.

ASP.NET MVC contiene una propria serie di aiutanti incorporati che proteggono contro CSRF utilizzando unico token passato in con la richiesta. Gli helper utilizzano non solo un campo di modulo nascosto richiesto, ma anche un valore del cookie, rendendo abbastanza un po' più difficile di forgiare una richiesta. Queste protezioni sono facili da implementare e assolutamente essenziale per integrare nelle vostre applicazioni. Per aggiungere @Html.AntiForgery­Token() all'interno di <form> a suo parere, procedere come segue:

@using (Html.BeginForm())
{
  @Html.AntiForgeryToken();
  @Html.EditorForModel();
  <input type="submit" value="Submit" />
}
Decorate any controllers that accept post data with the [Validate­AntiForgeryToken], like so:
[HttpPost]
[ValidateAntiForgeryToken()]
public ActionResult Index(User user)
{
  ...
}

Vulnerabilità di comprensione

Questo articolo è guardato da cross-site scripting e cross-site request forgery, due modi comuni applicazioni Web sono hacked. Aggiunto a due coperto il mese scorso, SQL injection e parametro manomissione, ora avete una buona comprensione di come le applicazioni possono essere vulnerabili.

Hai visto anche quanto sia facile per costruire la sicurezza nelle applicazioni per la protezione contro alcuni degli attacchi più comuni. Se si hai già state costruendo sicurezza nel vostro ciclo di sviluppo del software, grande! Se non l'hai fatto c'è il momento migliore per iniziare rispetto a oggi. Si possono controllare le applicazioni esistenti su base per pagina/a-modulo e nella maggior parte dei casi il refactoring li molto facilmente. E proteggere le vostre applicazioni con SSL per prevenire sniffing di credenziali. Ricordarsi di pensare a sicurezza, prima, durante e dopo lo sviluppo.

Adam Tuliper è un progettista software con Cegedim e sviluppa software per più di 20 anni. Egli è un oratore di comunità nazionale INETA e parla regolarmente a conferenze e.Gruppi di utenti NET. Lui check out su Twitter a twitter.com/AdamTuliper, sul suo blog a completedevelopment.blogspot.com o presso il nuovo sito Web di garantire la coding.com. Per più approfondite informazioni su hack proofing applicazione ASP.NET applicazioni, vedere la sua prossima serie di video di Pluralsight.

Grazie all'esperto tecnica seguente per la revisione di questo articolo: Barry Dorrans