Condividi tramite


Operazioni da eseguire e da evitare in ASP.NET

In questo argomento vengono descritti diversi errori comuni che gli utenti effettuano all'interno di ASP.NET progetti Web. Fornisce raccomandazioni per le operazioni da eseguire per evitare questi errori comuni. Si basa su una presentazione di Damian Edwards alla Norwegian Developers Conference.

Dichiarazione di non responsabilità

Questo argomento non è destinato a una guida completa per garantire che l'applicazione sia sicura ed efficiente. È comunque necessario seguire le procedure consigliate per la sicurezza e le prestazioni non descritte in questo argomento. Suggerisce solo come evitare errori comuni correlati a classi e processi .NET.

Panoramica

In questo argomento sono incluse le sezioni seguenti:

Conformità agli standard

Adattatori di controllo

Raccomandazione: interrompere l'uso di adattatori di controllo per il rendering adattivo e usare invece query multimediali CSS e HTML conforme agli standard.

Gli adattatori di controlli sono stati introdotti in .NET 2.0 per eseguire il rendering del codice di presentazione personalizzato per dispositivi e ambienti diversi. Ora, questo rendering adattivo può essere eseguito con CSS e HTML. È consigliabile interrompere l'uso degli adattatori di controllo e convertire eventuali adattatori esistenti in CSS e HTML.

Per altre informazioni, vedere Query multimediali e Procedura: Aggiungere pagine per dispositivi mobili all'applicazione Web Forms ASP.NET/MVC.

Proprietà di stile nei controlli

Raccomandazione: interrompere l'impostazione dei valori di stile nel markup del controllo e impostare invece i valori di formattazione nei fogli di stile CSS.

I controlli server Web contengono decine di proprietà che possono essere usate per impostare le proprietà di stile in linea. Ad esempio, la proprietà ForeColor imposta il colore del testo per un controllo . È possibile ottenere questo stesso effetto in modo più efficiente tramite fogli di stile CSS. I fogli di stile consentono di centralizzare i valori di stile ed evitare di impostare questi valori in tutta l'applicazione.

Nell'esempio seguente viene illustrata una classe CSS che imposta il testo su rosso.

.CautionRow {
    color: red;
}

Nell'esempio seguente viene illustrato come applicare dinamicamente la classe CSS.

protected void CustomersGridView_RowDataBound(object sender, GridViewRowEventArgs e)
{
    if (e.Row.Cells[2].Text == "Unconfirmed")
    {
        e.Row.CssClass = "CautionRow";
    }
}

Callback di pagina e controllo

Raccomandazione: interrompere l'uso dei callback di pagina e controllo e usare invece una delle opzioni seguenti: AJAX, UpdatePanel, metodi di azione MVC, API Web o SignalR.

Nelle versioni precedenti dei metodi di callback di ASP.NET, Page e Control consentono di aggiornare parte della pagina Web senza aggiornare un'intera pagina. È ora possibile eseguire aggiornamenti a pagina parziale tramite AJAX, UpdatePanel, MVC, API Web o SignalR. È consigliabile interrompere l'uso dei metodi di callback perché possono causare problemi con URL descrittivi e routing. Per impostazione predefinita, i controlli non abilitano i metodi di callback, ma se è stata abilitata questa funzionalità in un controllo, è necessario disabilitarla.

Rilevamento delle funzionalità del browser

Raccomandazione: interrompere l'uso del rilevamento delle funzionalità del browser statico e usare invece il rilevamento delle funzionalità dinamiche.

Nelle versioni precedenti di ASP.NET, le funzionalità supportate per ogni browser sono state archiviate in un file XML. Il rilevamento del supporto delle funzionalità tramite una ricerca statica non è l'approccio migliore. A questo punto, è possibile rilevare dinamicamente le funzionalità supportate da un browser usando un framework di rilevamento delle funzionalità, ad esempio Modernizr. Il rilevamento delle funzionalità determina il supporto tentando di usare un metodo o una proprietà e quindi verificando se il browser ha prodotto il risultato desiderato. Per impostazione predefinita, Modernizr è incluso nei modelli di applicazione Web.

Sicurezza

Convalida delle richieste

Raccomandazione: convalidare l'input dell'utente e codificare l'output degli utenti.

La convalida delle richieste è una funzionalità di ASP.NET che controlla ogni richiesta e arresta la richiesta se viene rilevata una minaccia percepita. Non dipende dalla convalida delle richieste per proteggere l'applicazione da attacchi di scripting tra siti. Convalidare invece tutti gli input degli utenti e codificare l'output. In alcuni casi limitati è possibile usare espressioni regolari per convalidare l'input, ma in casi più complessi è consigliabile convalidare l'input dell'utente usando classi .NET che determinano se il valore corrisponde ai valori consentiti.

Nell'esempio seguente viene illustrato come utilizzare un metodo statico nella classe Uri per determinare se l'URI fornito da un utente è valido.

var isValidUri = Uri.IsWellFormedUriString(passedUri, UriKind.Absolute);

Tuttavia, per verificare sufficientemente l'URI, è necessario controllare anche per assicurarsi che specifichi http o https. Nell'esempio seguente vengono utilizzati metodi di istanza per verificare che l'URI sia valido.

var uriToVerify = new Uri(passedUri);
var isValidUri = uriToVerify.IsWellFormedOriginalString();
var isValidScheme = uriToVerify.Scheme == "http" || uriToVerify.Scheme == "https";

Prima di eseguire il rendering dell'input dell'utente come HTML o includere l'input dell'utente in una query SQL, codificare i valori per assicurarsi che il codice dannoso non sia incluso.

È possibile codificare il valore nel markup con la <sintassi %: %> , come illustrato di seguito.

<span><%: userInput %></span>

In alternativa, nella sintassi Razor è possibile codificare HTML con @, come illustrato di seguito.

<span>@userInput</span>

Nell'esempio seguente viene illustrato come codificare html un valore nel code-behind.

var encodedInput = Server.HtmlEncode(userInput);

Per codificare in modo sicuro un valore per i comandi SQL, usare parametri di comando come SqlParameter.

Autenticazione e sessione basata su moduli senza cookie

Raccomandazione: richiedere i cookie.

Il passaggio delle informazioni di autenticazione nella stringa di query non è sicuro. Pertanto, richiedere i cookie quando l'applicazione include l'autenticazione. Se il cookie archivia informazioni riservate, è consigliabile richiedere SSL per il cookie.

Nell'esempio seguente viene illustrato come specificare nel file Web.config che l'autenticazione basata su form richiede un cookie trasmesso tramite SSL.

<authentication mode="Forms">
  <forms loginUrl="member_login.aspx"
    cookieless="UseCookies"
    requireSSL="true"
    path="/MyApplication" />
</authentication>

Enableviewstatemac

Raccomandazione: non impostare mai su false.

Per impostazione predefinita, EnableViewStateMac è impostato su true. Anche se l'applicazione non usa lo stato di visualizzazione, non impostare EnableViewStateMac su false. L'impostazione di questo valore su false rende l'applicazione vulnerabile allo scripting tra siti.

A partire da ASP.NET 4.5.2, il runtime applica EnableViewStateMac=true. Anche se lo si imposta su false, il runtime ignora questo valore e procede con il valore impostato su true. Per altre informazioni, vedere ASP.NET 4.5.2 e EnableViewStateMac.

Nell'esempio seguente viene illustrato come impostare EnableViewStateMac su true. Non è necessario impostare effettivamente questo valore su true perché è true per impostazione predefinita. Tuttavia, se è stato impostato su false in qualsiasi pagina dell'applicazione, è necessario correggere immediatamente questo valore.

<%@ Page language="C#" EnableViewStateMac="true" %>

Attendibilità media

Raccomandazione: non dipendere da attendibilità media (o da qualsiasi altro livello di attendibilità) come limite di sicurezza.

L'attendibilità parziale non protegge adeguatamente l'applicazione e non deve essere usata. Usare invece Attendibilità totale e isolare le applicazioni non attendibili in pool di applicazioni separati. Eseguire anche ogni pool di applicazioni con un'identità univoca. Per altre informazioni, vedere ASP.NET Trust parziale non garantisce l'isolamento dell'applicazione.

<appSettings>

Raccomandazione: non disabilitare le impostazioni di sicurezza nell'elemento <appSettings> .

L'elemento appSettings contiene molti valori necessari per gli aggiornamenti della sicurezza. Non è consigliabile modificare o disabilitare questi valori. Se è necessario disabilitare questi valori durante la distribuzione di un aggiornamento, riabilitare immediatamente dopo il completamento della distribuzione.

Per informazioni dettagliate, vedere ASP.NET elemento appSettings.

UrlPathEncode

Raccomandazione: usare urlEncode .

Il metodo UrlPathEncode è stato aggiunto a .NET Framework per risolvere un problema di compatibilità del browser molto specifico. Non codifica adeguatamente un URL e non protegge l'applicazione dallo script tra siti. Non è mai consigliabile usarlo nell'applicazione. Usare invece UrlEncode.

Nell'esempio seguente viene illustrato come passare un URL codificato come parametro stringa di query per un controllo collegamento ipertestuale.

string destinationURL = "http://www.contoso.com/default.aspx?user=test";
NextPage.NavigateUrl = "~/Finish?url=" + Server.UrlEncode(destinationURL);

Affidabilità e prestazioni

PreSendRequestHeaders e PreSendRequestContent

Raccomandazione: non usare questi eventi con moduli gestiti. Scrivere invece un modulo IIS nativo per eseguire l'attività richiesta. Vedere Creazione di moduli HTTP Native-Code.

È possibile usare gli eventi PreSendRequestHeaders e PreSendRequestContent con moduli IIS nativi.

Avviso

Non usare PreSendRequestHeaders e PreSendRequestContent con moduli gestiti che implementano IHttpModule. L'impostazione di queste proprietà può causare problemi con le richieste asincrone. La combinazione di routing richiesto dall'applicazione (ARR) e websocket potrebbe causare l'arresto anomalo delle eccezioni di accesso alle violazioni che possono causare l'arresto anomalo di w3wp. Ad esempio, iiscore! W3_CONTEXT_BASE::GetIsLastNotification+68 in iiscore.dll ha causato un'eccezione di violazione di accesso (0xC0000005).

Eventi di pagina asincroni con i moduli Web

Raccomandazione: in Web Forms evitare di scrivere metodi void asincroni per gli eventi del ciclo di vita della pagina e usare invece Page.RegisterAsyncTask per il codice asincrono.

Quando si contrassegna un evento di pagina con asincronae void, non è possibile determinare al termine del codice asincrono. Usare invece Page.RegisterAsyncTask per eseguire il codice asincrono in modo che consenta di tenere traccia del completamento.

Nell'esempio seguente viene illustrato un gestore di clic del pulsante che contiene codice asincrono. Questo esempio include la lettura di un valore stringa in modo asincrono, che viene fornito solo come esempio semplificato di un'attività asincrona e non come procedura consigliata.

protected void StartAsync_Click(object sender, EventArgs e)
{
    Page.RegisterAsyncTask(new PageAsyncTask(async() =>
    {
        string stringToRead = "Long text value";

        using (StringReader reader = new StringReader(stringToRead))
        {
            string readText = await reader.ReadToEndAsync();
            Result.Text = readText;
        }
    }));
}

Se si usano attività asincrone, impostare il framework di destinazione del runtime Http su 4.5 (o versione successiva) nel file Web.config. L'impostazione del framework di destinazione su 4.5 attiva il nuovo contesto di sincronizzazione aggiunto in .NET 4.5. Questo valore viene impostato per impostazione predefinita nei nuovi progetti in Visual Studio, ma non viene impostato se si usa un progetto esistente.

<system.web>
    <httpRuntime TargetFramework="4.5" />
</system.web>

Lavoro da fuoco e dimenticare

Raccomandazione: quando si gestisce una richiesta all'interno di ASP.NET, evitare l'avvio del lavoro fire-and-forget (ad esempio chiamando il metodo ThreadPool.QueueUserWorkItem o creando un timer che chiama ripetutamente un delegato).

Se l'applicazione ha un lavoro fire-and-forget che viene eseguito all'interno di ASP.NET, l'applicazione può uscire dalla sincronizzazione. In qualsiasi momento, il dominio dell'app può essere distrutto, il che significa che il processo in corso potrebbe non corrispondere più allo stato corrente dell'applicazione.

È consigliabile spostare questo tipo di lavoro all'esterno di ASP.NET. È possibile usare processi Web, servizio Windows o un ruolo di lavoro in Azure per eseguire il lavoro in corso ed eseguire tale codice da un altro processo.

Se è necessario eseguire questo lavoro all'interno di ASP.NET, è possibile aggiungere il pacchetto Nuget denominato WebBackgrounder per eseguire il codice.

Corpo dell'entità richiesta

Raccomandazione: evitare di leggere Request.Form o Request.InputStream prima dell'evento di esecuzione del gestore.

La prima lettura da Request.Form o Request.InputStream è durante l'evento di esecuzione del gestore. In MVC il controller è il gestore e l'evento execute è quando viene eseguito il metodo di azione. In Web Forms, la pagina è il gestore e l'evento execute è quando viene generato l'evento Page.Init. Se si legge il corpo dell'entità della richiesta prima dell'evento di esecuzione, si interferisce con l'elaborazione della richiesta.

Se è necessario leggere il corpo dell'entità richiesta prima dell'evento di esecuzione, usare Request.GetBufferlessInputStream o Request.GetBufferedInputStream. Quando si usa GetBufferlessInputStream, si ottiene il flusso non elaborato dalla richiesta e si presuppone la responsabilità di elaborare l'intera richiesta. Dopo aver chiamato GetBufferlessInputStream, Request.Form e Request.InputStream non sono disponibili perché non sono stati popolati da ASP.NET. Quando si usa GetBufferedInputStream, si ottiene una copia del flusso dalla richiesta. Request.Form e Request.InputStream sono ancora disponibili più avanti nella richiesta perché ASP.NET popola l'altra copia.

Response.Redirect e Response.End

Raccomandazione: tenere presente le differenze nel modo in cui il thread viene gestito dopo aver chiamato Response.Redirect(String)..

Il metodo Response.Redirect(String) chiama il metodo Response.End. In un processo sincrono, la chiamata a Request.Redirect causa l'interruzione immediata del thread corrente. Tuttavia, in un processo asincrono, la chiamata a Response.Redirect non interrompe il thread corrente, quindi l'esecuzione del codice continua per la richiesta. In un processo asincrono, è necessario restituire l'oggetto Task dal metodo per arrestare l'esecuzione del codice.

In un progetto MVC non è necessario chiamare Response.Redirect. Restituisce invece un reindirizzamentoResult.

EnableViewState e ViewStateMode

Raccomandazione: usare ViewStateMode, invece di EnableViewState, per fornire un controllo granulare sui controlli che usano lo stato di visualizzazione.

Quando si imposta EnableViewState su false nella direttiva Pagina, lo stato di visualizzazione è disabilitato per tutti i controlli all'interno della pagina e non può essere abilitato. Se si vuole abilitare lo stato di visualizzazione solo per determinati controlli nella pagina, impostare ViewStateMode su Disabilitato per la pagina.

<%@ Page ViewStateMode="Disabled" . . . %>

Impostare quindi ViewStateMode su Abilitato solo sui controlli che richiedono effettivamente lo stato di visualizzazione.

<asp:GridView ViewStateMode="Enabled" runat="server">

Abilitando lo stato di visualizzazione solo per i controlli necessari, è possibile ridurre le dimensioni dello stato di visualizzazione per le pagine Web.

SqlMembershipProvider

Raccomandazione: usare provider universali.

Nei modelli di progetto correnti SqlMembershipProvider è stato sostituito da provider universali ASP.NET, disponibile come pacchetto NuGet. Se si usa SqlMembershipProvider in un progetto compilato con una versione precedente dei modelli, è necessario passare a provider universali. Il provider universali usare tutti i database supportati da Entity Framework.

Per altre informazioni, vedere Introduzione provider universali ASP.NET.

Richieste a esecuzione prolungata (>110 secondi)

Raccomandazione: usare WebSocket o SignalR per i client connessi e usare operazioni di I/O asincrone.

Le richieste a esecuzione prolungata possono causare risultati imprevedibili e prestazioni scarse nell'applicazione Web. L'impostazione di timeout predefinita per una richiesta è di 110 secondi. Se si usa lo stato della sessione con una richiesta a esecuzione prolungata, ASP.NET rilascia il blocco sull'oggetto Session dopo 110 secondi. Tuttavia, l'applicazione potrebbe trovarsi al centro di un'operazione sull'oggetto Session quando il blocco viene rilasciato e l'operazione potrebbe non essere completata correttamente. Se una seconda richiesta dall'utente viene bloccata durante l'esecuzione della prima richiesta, la seconda richiesta potrebbe accedere all'oggetto Session in uno stato incoerente.

Se l'applicazione include operazioni di I/O di blocco (o sincrone), l'applicazione non risponderà.

Per migliorare le prestazioni, usare le operazioni di I/O asincrone in .NET Framework. Usare anche WebSocket o SignalR per connettere i client al server. Queste funzionalità sono progettate per gestire in modo efficiente le richieste a esecuzione prolungata.