Condividi tramite


Protezione delle stringhe di connessione e di altre informazioni di configurazione (VB)

di Scott Mitchell

Scaricare il PDF

Un'applicazione ASP.NET archivia in genere le informazioni di configurazione in un file Web.config. Alcune di queste informazioni sono sensibili e giustificano la protezione. Per impostazione predefinita, questo file non verrà servito a un visitatore del sito Web, ma un amministratore o un hacker può accedere al file system del server Web e visualizzare il contenuto del file. In questa esercitazione si apprenderà che ASP.NET 2.0 consente di proteggere le informazioni riservate crittografando le sezioni del file Web.config.

Introduzione

Le informazioni di configurazione per le applicazioni ASP.NET vengono in genere archiviate in un file XML denominato Web.config. Nel corso di queste esercitazioni abbiamo aggiornato il Web.config un numero limitato di volte. Quando si crea il Northwind set di dati tipizzato nella prima esercitazione, ad esempio, le informazioni sulla stringa di connessione sono state aggiunte automaticamente a Web.config nella sezione <connectionStrings>. Più avanti, nell'esercitazione Pagine master e navigazione del sito, abbiamo aggiornato manualmente Web.config, aggiungendo un elemento <pages> che indica che tutte le pagine di ASP.NET del nostro progetto devono utilizzare il tema DataWebControls.

Poiché Web.config può contenere dati sensibili, ad esempio stringa di connessione, è importante che il contenuto di Web.config venga mantenuto al sicuro e nascosto ai visualizzatori non autorizzati. Per impostazione predefinita, qualsiasi richiesta HTTP a un file con estensione .config viene gestita dal motore di ASP.NET, che restituisce il messaggio Questo tipo di pagina non viene fornito nella figura 1. Ciò significa che i visitatori non possono visualizzare il Web.config contenuto del file semplicemente immettendo http://www.YourServer.com/Web.config nella barra degli indirizzi del browser.

Visitare Web.config tramite un browser restituisce un messaggio che indica che questo tipo di pagina non viene servita

Figura 1: La visita Web.config tramite un browser restituisce un messaggio di questo tipo di pagina non servito (fare clic per visualizzare l'immagine a dimensione intera)

Ma cosa succede se un utente malintenzionato è in grado di trovare un altro exploit che le consente di visualizzare il Web.config contenuto del file? Cosa può fare un utente malintenzionato con queste informazioni e quali passaggi possono essere eseguiti per proteggere ulteriormente le informazioni riservate all'interno Web.configdi ? Fortunatamente, la maggior parte delle sezioni di Web.config non contiene informazioni riservate. Quale danno può essere commesso da un utente malintenzionato se conoscono il nome del tema predefinito usato dalle pagine ASP.NET?

Alcune Web.config sezioni, tuttavia, contengono informazioni riservate che possono includere stringa di connessione, nomi utente, password, nomi dei server, chiavi di crittografia e così via. Queste informazioni sono in genere disponibili nelle sezioni seguenti Web.config :

  • <appSettings>
  • <connectionStrings>
  • <identity>
  • <sessionState>

In questa esercitazione verranno esaminate le tecniche per proteggere tali informazioni di configurazione riservate. Come si vedrà, .NET Framework versione 2.0 include un sistema di configurazioni protette che esegue la crittografia e la decrittografia delle sezioni di configurazione selezionate a livello di codice.

Annotazioni

Questa esercitazione si conclude con un'analisi delle raccomandazioni di Microsoft per la connessione a un database da un'applicazione ASP.NET. Oltre a crittografare i stringa di connessione, è possibile rafforzare il sistema assicurandosi di connettersi al database in modo sicuro.

Passaggio 1: Esplorazione delle opzioni di configurazione protette di ASP.NET 2.0

ASP.NET 2.0 include un sistema di configurazione protetto per crittografare e decrittografare le informazioni di configurazione. Sono inclusi i metodi in .NET Framework che possono essere usati per crittografare o decrittografare le informazioni di configurazione a livello di codice. Il sistema di configurazione protetto usa il modello di provider che consente agli sviluppatori di scegliere l'implementazione crittografica usata.

.NET Framework viene fornito con due provider di configurazione protetti:

Poiché il sistema di configurazione protetto implementa il modello di progettazione del provider, è possibile creare un provider di configurazione protetto e collegarlo all'applicazione. Per ulteriori informazioni su questo processo, consultare Implementazione di un provider di configurazione protetta.

I provider RSA e DPAPI usano le chiavi per le routine di crittografia e decrittografia e queste chiavi possono essere archiviate a livello di computer o utente. Le chiavi a livello di computer sono ideali per scenari in cui l'applicazione Web viene eseguita nel proprio server dedicato o se sono presenti più applicazioni in un server che devono condividere informazioni crittografate. Le chiavi a livello di utente sono un'opzione più sicura negli ambienti di hosting condiviso in cui altre applicazioni nello stesso server non devono essere in grado di decrittografare le sezioni di configurazione protetta dell'applicazione.

In questa esercitazione gli esempi useranno il provider DPAPI e le chiavi a livello di computer. In particolare, verrà esaminata la crittografia della <connectionStrings> sezione in Web.config, anche se il sistema di configurazione protetto può essere usato per crittografare la maggior parte delle Web.config sezioni. Per informazioni sull'uso di chiavi a livello di utente o sull'uso del provider RSA, consultare le risorse nella sezione Ulteriori letture alla fine di questa esercitazione.

Annotazioni

I provider RSAProtectedConfigurationProvider e DPAPIProtectedConfigurationProvider vengono registrati nel file machine.config con i nomi dei provider RsaProtectedConfigurationProvider e DataProtectionConfigurationProvider rispettivamente. Quando si crittografa o si decrittografano le informazioni di configurazione, sarà necessario specificare il nome del provider appropriato (RsaProtectedConfigurationProvider o DataProtectionConfigurationProvider) anziché il nome effettivo del tipo (RSAProtectedConfigurationProvider e DPAPIProtectedConfigurationProvider). È possibile trovare il machine.config file nella $WINDOWS$\Microsoft.NET\Framework\version\CONFIG cartella .

Passaggio 2: Crittografare e decrittografare le sezioni di configurazione a livello di codice

Con alcune righe di codice è possibile crittografare o decrittografare una determinata sezione di configurazione usando un provider specificato. Il codice, come si vedrà a breve, deve semplicemente fare riferimento alla sezione di configurazione appropriata a livello di codice, chiamare il ProtectSection metodo o UnprotectSection e quindi chiamare il Save metodo per rendere persistenti le modifiche. Inoltre, .NET Framework include un'utilità della riga di comando utile in grado di crittografare e decrittografare le informazioni di configurazione. Questa utilità della riga di comando verrà esaminata nel passaggio 3.

Per illustrare la protezione a livello di codice delle informazioni di configurazione, creare una pagina di ASP.NET che include pulsanti per crittografare e decrittografare la <connectionStrings> sezione in Web.config.

Per iniziare, aprire la EncryptingConfigSections.aspx pagina nella AdvancedDAL cartella . Trascinare un controllo TextBox dalla casella degli strumenti nella finestra di progettazione, impostandone la ID proprietà su WebConfigContents, la relativa TextMode proprietà su MultiLine e le relative proprietà Width e Rows rispettivamente su 95% e 15. Questo controllo TextBox visualizzerà il contenuto di Web.config, permettendoci di vedere rapidamente se è crittografato o meno. Naturalmente, in un'applicazione reale non si vuole mai visualizzare il contenuto di Web.config.

Sotto il controllo TextBox aggiungere due controlli Button denominati EncryptConnStrings e DecryptConnStrings. Impostare le relative proprietà di testo su Crittografa stringhe di connessione e Decrittografa stringhe di connessione.

A questo punto la schermata dovrebbe essere simile alla figura 2.

Screenshot che mostra Visual Studio aperto sulla pagina EncryptingConfigSections.aspx, con un nuovo TextBox e due pulsanti.

Figura 2: Aggiungere un controllo Web TextBox e due pulsanti alla pagina (fare clic per visualizzare l'immagine a dimensione intera)

Successivamente, è necessario scrivere codice che carica e visualizza il contenuto di Web.config in WebConfigContents TextBox al primo caricamento della pagina. Aggiungere il codice seguente alla classe code-behind della pagina. Questo codice aggiunge un metodo denominato DisplayWebConfig e lo chiama dal Page_Load gestore eventi quando Page.IsPostBack è False:

Protected Sub Page_Load(sender As Object, e As EventArgs) Handles Me.Load
    'On the first page visit, call DisplayWebConfig method
    If Not Page.IsPostBack Then
        DisplayWebConfig()
    End If
End Sub
Private Sub DisplayWebConfig()
    'Reads in the contents of Web.config and displays them in the TextBox
    Dim webConfigStream As StreamReader = _
        File.OpenText(Path.Combine(Request.PhysicalApplicationPath, "Web.config"))
    Dim configContents As String = webConfigStream.ReadToEnd()
    webConfigStream.Close()
    WebConfigContents.Text = configContents
End Sub

Il DisplayWebConfig metodo usa la File classe per aprire il file dell'applicazione Web.config , la StreamReader classe per leggerne il contenuto in una stringa e la Path classe per generare il percorso fisico del Web.config file. Queste tre classi sono tutte presenti nello spazio dei System.IO nomi. Di conseguenza, sarà necessario aggiungere un'istruzione Imports``System.IO all'inizio della classe code-behind o, in alternativa, anteporre questi nomi di classe con System.IO.

Successivamente, è necessario aggiungere gestori eventi per i due eventi dei controlli Click Button e aggiungere il codice necessario per crittografare e decrittografare la <connectionStrings> sezione usando una chiave a livello di computer con il provider DPAPI. Nella finestra di progettazione fare doppio clic su ognuno dei pulsanti per aggiungere un Click gestore eventi nella classe code-behind e quindi aggiungere il codice seguente:

Protected Sub EncryptConnStrings_Click(sender As Object, e As EventArgs) _
    Handles EncryptConnStrings.Click
    'Get configuration information about Web.config
    Dim config As Configuration = _
        WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath)
    ' Let's work with the <connectionStrings> section
    Dim connectionStrings As ConfigurationSection = _
        config.GetSection("connectionStrings")
    If connectionStrings IsNot Nothing Then
        ' Only encrypt the section if it is not already protected
        If Not connectionStrings.SectionInformation.IsProtected Then
            ' Encrypt the <connectionStrings> section using the 
            ' DataProtectionConfigurationProvider provider
            connectionStrings.SectionInformation.ProtectSection( _
                "DataProtectionConfigurationProvider")
            config.Save()
            ' Refresh the Web.config display
            DisplayWebConfig()
        End If
    End If
End Sub
Protected Sub DecryptConnStrings_Click(sender As Object, e As EventArgs) _
    Handles DecryptConnStrings.Click
    ' Get configuration information about Web.config
    Dim config As Configuration = _
        WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath)
    ' Let's work with the <connectionStrings> section
    Dim connectionStrings As ConfigurationSection = _
        config.GetSection("connectionStrings")
    If connectionStrings IsNot Nothing Then
        ' Only decrypt the section if it is protected
        If connectionStrings.SectionInformation.IsProtected Then
            ' Decrypt the <connectionStrings> section
            connectionStrings.SectionInformation.UnprotectSection()
            config.Save()
            ' Refresh the Web.config display
            DisplayWebConfig()
        End If
    End If
End Sub

Il codice usato nei due gestori eventi è quasi identico. Entrambi iniziano raccogliendo informazioni sul file dell'applicazione corrente tramite la classe e il metodo . Questo metodo restituisce il file di configurazione Web per il percorso virtuale specificato. Quindi, la sezione del file è accessibile tramite il metodo della classe , che restituisce un oggetto.

L'oggetto ConfigurationSection include una SectionInformation proprietà che fornisce informazioni e funzionalità aggiuntive relative alla sezione di configurazione. Come illustrato nel codice precedente, è possibile determinare se la sezione di configurazione è crittografata controllando la proprietà SectionInformation di IsProtected. Inoltre, la sezione può essere crittografata o decrittografata tramite la proprietà SectionInformation e i metodi ProtectSection(provider) e UnprotectSection.

Il ProtectSection(provider) metodo accetta come input una stringa che specifica il nome del provider di configurazione protetto da usare durante la crittografia. EncryptConnString Nel gestore eventi button s passiamo DataProtectionConfigurationProvider al ProtectSection(provider) metodo in modo che venga usato il provider DPAPI. Il UnprotectSection metodo può determinare il provider usato per crittografare la sezione di configurazione e pertanto non richiede parametri di input.

Dopo aver chiamato il metodo ProtectSection(provider) o UnprotectSection, è necessario chiamare il metodo Save dell'oggetto Configuration per rendere persistenti le modifiche. Dopo che le informazioni di configurazione sono state crittografate o decrittografate e le modifiche salvate, viene chiamato DisplayWebConfig per caricare il contenuto aggiornato Web.config nel controllo TextBox.

Dopo aver immesso il codice precedente, testarlo visitando la EncryptingConfigSections.aspx pagina tramite un browser. Inizialmente dovrebbe essere visualizzata una pagina che elenca il contenuto di Web.config con la <connectionStrings> sezione visualizzata in testo normale (vedere la figura 3).

Screenshot che mostra la pagina EncryptingConfigSections.aspx caricata in un Web browser.

Figura 3: Aggiungere un controllo Web TextBox e due pulsanti alla pagina (fare clic per visualizzare l'immagine a dimensione intera)

Fare ora clic sul pulsante Crittografa stringhe di connessione. Se la convalida della richiesta è abilitata, il markup inviato da WebConfigContents TextBox genererà un oggetto HttpRequestValidationException, che visualizza il messaggio: è stato rilevato un valore Request.Form potenzialmente pericoloso dal client. La convalida delle richieste, abilitata per impostazione predefinita in ASP.NET 2.0, impedisce i postback che includono codice HTML non codificato ed è progettata per impedire attacchi di tipo script injection. Questo controllo può essere disabilitato a livello di pagina o applicazione. Per disattivarla per questa pagina, impostare l'impostazione ValidateRequest su False nella direttiva @Page. La @Page direttiva si trova nella parte superiore del markup dichiarativo della pagina.

<%@ Page ValidateRequest="False" ... %>

Per altre informazioni sulla convalida delle richieste, lo scopo, come disabilitarlo a livello di pagina e applicazione, nonché su come codificare codice HTML, vedere Convalida delle richieste - Prevenzione degli attacchi di script.

Dopo aver disabilitato la convalida della richiesta per la pagina, provare a fare di nuovo clic sul pulsante Crittografa stringhe di connessione. Nel postback, si accederà al file di configurazione e la sezione <connectionStrings> verrà crittografata utilizzando il provider DPAPI. TextBox viene quindi aggiornata per visualizzare il nuovo Web.config contenuto. Come illustrato nella figura 4, le <connectionStrings> informazioni sono ora crittografate.

Facendo clic sul pulsante Crittografa stringhe di connessione viene crittografata la <sezione connectionString>

Figura 4: Fare clic sul pulsante Crittografa stringhe di connessione crittografa la sezione (fare clic per visualizzare l'immagine <connectionString>a dimensione intera)

La sezione crittografata <connectionStrings> generata nel computer segue, anche se alcuni dei contenuti nell'elemento <CipherData> sono stati rimossi per brevità:

<connectionStrings 
    configProtectionProvider="DataProtectionConfigurationProvider">
  <EncryptedData>
    <CipherData>
      <CipherValue>==</CipherValue>
    </CipherData>
  </EncryptedData>
</connectionStrings>

Annotazioni

L'elemento <connectionStrings> specifica il provider utilizzato per eseguire la crittografia (DataProtectionConfigurationProvider). Queste informazioni vengono utilizzate dal UnprotectSection metodo quando si fa clic sul pulsante Decrittografa stringhe di connessione.

Quando si accede alle informazioni sulla stringa di connessione da Web.config, sia tramite il codice che scriviamo, da un controllo SqlDataSource, o dal codice generato automaticamente dagli oggetti TableAdapter nei nostri set di dati tipizzati, vengono decrittografate automaticamente. In breve, non è necessario aggiungere codice aggiuntivo o logica per decrittografare la sezione crittografata <connectionString> . Per dimostrare questo problema, visitare una delle esercitazioni precedenti in questo momento, ad esempio l'esercitazione Visualizzazione semplice della sezione Report di base (~/BasicReporting/SimpleDisplay.aspx). Come mostra la figura 5, l'esercitazione funziona esattamente come ci si aspetterebbe, ciò indica che le informazioni della stringa di connessione crittografate vengono decrittografate automaticamente dalla pagina ASP.NET.

Il livello di accesso ai dati decrittografa automaticamente le informazioni sulla stringa di connessione

Figura 5: Il livello di accesso ai dati decrittografa automaticamente le informazioni sulla stringa di connessione (fare clic per visualizzare l'immagine a dimensione intera)

Per ripristinare la sezione <connectionStrings> alla sua rappresentazione in testo normale, fare clic sul pulsante Decrittografa stringhe di connessione. Quando si verifica il postback, dovrebbe essere visualizzata la stringa di connessione in Web.config in chiaro. A questo punto la schermata dovrebbe essere simile alla prima volta che si visita questa pagina (vedere la figura 3).

Passaggio 3: Crittografia delle sezioni di configurazione tramite aspnet_regiis.exe

.NET Framework include un'ampia gamma di strumenti da riga di comando nella $WINDOWS$\Microsoft.NET\Framework\version\ cartella . Nell'esercitazione Uso delle dipendenze della cache SQL, ad esempio, abbiamo esaminato l'uso dello aspnet_regsql.exe strumento da riga di comando per aggiungere l'infrastruttura necessaria per le dipendenze della cache SQL. Un altro strumento da riga di comando utile in questa cartella è lo strumento di registrazione IIS ASP.NET (aspnet_regiis.exe). Come suggerisce il nome, lo strumento di registrazione IIS ASP.NET viene usato principalmente per registrare un'applicazione ASP.NET 2.0 con il server Web di livello professionale Microsoft, IIS. Oltre alle funzionalità correlate a IIS, lo strumento di registrazione IIS ASP.NET può essere usato anche per crittografare o decrittografare le sezioni di configurazione specificate in Web.config.

L'istruzione seguente illustra la sintassi generale usata per crittografare una sezione di configurazione con lo strumento da aspnet_regiis.exe riga di comando:

aspnet_regiis.exe -pef section physical_directory -prov provider

La sezione è quella di configurazione da crittografare (ad esempio connectionStrings), physical_directory è il percorso fisico completo della directory radice dell'applicazione web e provider è il nome del provider di configurazione protetto da usare, come DataProtectionConfigurationProvider. In alternativa, se l'applicazione Web è registrata in IIS, è possibile immettere il percorso virtuale anziché il percorso fisico usando la sintassi seguente:

aspnet_regiis.exe -pe section -app virtual_directory -prov provider

L'esempio seguente aspnet_regiis.exe crittografa la <connectionStrings> sezione usando il provider DPAPI con una chiave a livello di computer:

aspnet_regiis.exe -pef
"connectionStrings" "C:\Websites\ASPNET_Data_Tutorial_73_VB"
-prov "DataProtectionConfigurationProvider"

Lo strumento a riga di comando aspnet_regiis.exe può essere usato per decrittografare le sezioni di configurazione. Anziché usare l'opzione -pef , usare -pdf (o invece di -pe, usare -pd). Si noti inoltre che il nome del provider non è necessario durante la decrittografia.

aspnet_regiis.exe -pdf section physical_directory
  -- or --
aspnet_regiis.exe -pd section -app virtual_directory

Annotazioni

Poiché si usa il provider DPAPI, che usa chiavi specifiche per il computer, è necessario eseguire aspnet_regiis.exe dallo stesso computer da cui vengono gestite le pagine Web. Ad esempio, se si esegue questo programma da riga di comando dal computer di sviluppo locale e quindi si carica il file Web.config crittografato nel server di produzione, il server di produzione non sarà in grado di decrittografare le informazioni stringa di connessione poiché è stato crittografato usando chiavi specifiche per il computer di sviluppo. Il provider RSA non ha questa limitazione perché è possibile esportare le chiavi RSA in un altro computer.

Informazioni sulle opzioni di autenticazione del database

Prima che qualsiasi applicazione possa eseguire SELECTquery , INSERT, UPDATEo DELETE a un database di Microsoft SQL Server, il database deve prima identificare il richiedente. Questo processo è noto come autenticazione e SQL Server offre due metodi di autenticazione:

  • Autenticazione di Windows: processo in cui viene eseguita l'applicazione per comunicare con il database. Quando si esegue un'applicazione ASP.NET tramite Visual Studio 2005 s ASP.NET Development Server, l'applicazione ASP.NET presuppone l'identità dell'utente attualmente connesso. Per le applicazioni ASP.NET su Microsoft Internet Information Server (IIS), le applicazioni ASP.NET in genere assumono l'identità di domainName``\MachineName o domainName``\NETWORK SERVICE, anche se può essere personalizzata.
  • Autenticazione SQL: i valori di ID utente e password vengono forniti come credenziali per l'autenticazione. Con l'autenticazione SQL, l'ID utente e la password vengono forniti nella stringa di connessione.

autenticazione di Windows è preferibile rispetto all'autenticazione SQL perché è più sicura. Con l'autenticazione di Windows, la stringa di connessione è priva di un nome utente e di una password, e se il server web e il server di database risiedono su due computer diversi, le credenziali non vengono inviate sulla rete in testo in chiaro. Con l'autenticazione SQL, tuttavia, le credenziali di autenticazione vengono hardcoded nel stringa di connessione e vengono trasmesse dal server Web al server di database in testo normale.

Queste esercitazioni hanno usato autenticazione di Windows. È possibile indicare la modalità di autenticazione usata esaminando il stringa di connessione. La stringa di connessione in Web.config per le esercitazioni è stata:

Data Source=.\SQLEXPRESS; AttachDbFilename=|DataDirectory|\NORTHWND.MDF; Integrated Security=True; User Instance=True

"Integrated Security=True" e la mancanza di un nome utente e di una password indicano che viene usata l'autenticazione di Windows. In alcune stringhe di connessione i termini Trusted Connection=Yes o Integrated Security=SSPI sono usati invece di Integrated Security=True, ma tutti e tre indicano l'uso dell'autenticazione di Windows.

Nell'esempio seguente viene illustrata una stringa di connessione che utilizza l'autenticazione SQL. Si notino le credenziali incorporate all'interno della stringa di connessione:

Server=serverName; Database=Northwind; uid=userID; pwd=password

Immagina che un utente malintenzionato sia in grado di visualizzare il file dell'applicazione Web.config. Se si usa l'autenticazione SQL per connettersi a un database accessibile tramite Internet, l'utente malintenzionato può usare questa stringa di connessione per connettersi al database tramite SQL Management Studio o dalle pagine di ASP.NET nel proprio sito Web. Per attenuare questa minaccia, crittografare le informazioni di stringa di connessione in Web.config usando il sistema di configurazione protetto.

Annotazioni

Per altre informazioni sui diversi tipi di autenticazione disponibili in SQL Server, vedere Building Secure ASP.NET Applications: Authentication, Authorization e Secure Communication. Per ulteriori esempi di stringhe di connessione che illustrano le differenze tra la sintassi di autenticazione di Windows e SQL, consultare ConnectionStrings.com.

Riassunto

Per impostazione predefinita, non è possibile accedere ai file con estensione .config in un'applicazione ASP.NET tramite un browser. Questi tipi di file non vengono restituiti perché possono contenere informazioni riservate, ad esempio stringa di connessione di database, nomi utente e password e così via. Il sistema di configurazione protetto in .NET 2.0 consente di proteggere ulteriormente le informazioni riservate consentendo la crittografia delle sezioni di configurazione specificate. Esistono due provider di configurazione protetti predefiniti: uno che usa l'algoritmo RSA e uno che usa l'API Protezione dati di Windows (DPAPI).

In questa esercitazione è stato illustrato come crittografare e decrittografare le impostazioni di configurazione usando il provider DPAPI. Questa operazione può essere eseguita sia a livello di codice, come illustrato nel passaggio 2, sia tramite lo strumento da aspnet_regiis.exe riga di comando, illustrato nel passaggio 3. Per altre informazioni sull'uso di chiavi a livello di utente o sull'uso del provider RSA, vedere invece le risorse nella sezione Altre informazioni.

Buon programmatori!

Altre informazioni

Per altre informazioni sugli argomenti illustrati in questa esercitazione, vedere le risorse seguenti:

Informazioni sull'autore

Scott Mitchell, autore di sette libri ASP/ASP.NET e fondatore di 4GuysFromRolla.com, ha lavorato con le tecnologie Web Microsoft dal 1998. Scott lavora come consulente indipendente, formatore e scrittore. Il suo ultimo libro è Sams Teach Yourself ASP.NET 2.0 in 24 ore. Può essere raggiunto a mitchell@4GuysFromRolla.com.

Grazie speciale a

Questa serie di esercitazioni è stata esaminata da molti revisori competenti. I principali revisori di questo tutorial erano Teresa Murphy e Randy Schmidt. Si è interessati a esaminare i prossimi articoli MSDN? In tal caso, mandami un messaggio a mitchell@4GuysFromRolla.com.