Protezione delle stringhe di connessione e di altre informazioni di configurazione (C#)
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 sono state aggiornate alcune Web.config
volte. Quando si crea il Northwind
set di dati tipizzato nella prima esercitazione, ad esempio, stringa di connessione informazioni sono state aggiunte automaticamente a Web.config
nella <connectionStrings>
sezione . Più avanti, nell'esercitazione Pagine master e navigazione sito, è stato aggiornato Web.config
manualmente , aggiungendo un <pages>
elemento che indica che tutte le pagine ASP.NET nel progetto devono usare il DataWebControls
tema.
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.
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.config
di ? 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.
Nota
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:
RSAProtectedConfigurationProvider
: usa l'algoritmo RSA asimmetrico per la crittografia e la decrittografia.DPAPIProtectedConfigurationProvider
: usa l'API Protezione dati di Windows (DPAPI) per la crittografia e la decrittografia.
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 altre informazioni su questo processo, vedere Implementazione di un provider di configurazione protetto.
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.
Nota
I RSAProtectedConfigurationProvider
provider e DPAPIProtectedConfigurationProvider
vengono registrati rispettivamente nel machine.config
file con i nomi dei provider RsaProtectedConfigurationProvider
e DataProtectionConfigurationProvider
. 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à e Width
Rows
rispettivamente su 95% e 15. Questo controllo TextBox visualizzerà il contenuto che consente di Web.config
verificare rapidamente se il contenuto è 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.
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 void Page_Load(object sender, EventArgs e)
{
// On the first page visit, call DisplayWebConfig method
if (!Page.IsPostBack)
DisplayWebConfig();
}
private void DisplayWebConfig()
{
// Reads in the contents of Web.config and displays them in the TextBox
StreamReader webConfigStream =
File.OpenText(Path.Combine(Request.PhysicalApplicationPath, "Web.config"));
string configContents = webConfigStream.ReadToEnd();
webConfigStream.Close();
WebConfigContents.Text = configContents;
}
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 disponibili nello spazio dei System.IO
nomi . Di conseguenza, sarà necessario aggiungere un'istruzione using
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 void EncryptConnStrings_Click(object sender, EventArgs e)
{
// Get configuration information about Web.config
Configuration config =
WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath);
// Let's work with the <connectionStrings> section
ConfigurationSection connectionStrings = config.GetSection("connectionStrings");
if (connectionStrings != null)
// Only encrypt the section if it is not already protected
if (!connectionStrings.SectionInformation.IsProtected)
{
// Encrypt the <connectionStrings> section using the
// DataProtectionConfigurationProvider provider
connectionStrings.SectionInformation.ProtectSection(
"DataProtectionConfigurationProvider");
config.Save();
// Refresh the Web.config display
DisplayWebConfig();
}
}
protected void DecryptConnStrings_Click(object sender, EventArgs e)
{
// Get configuration information about Web.config
Configuration config =
WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath);
// Let's work with the <connectionStrings> section
ConfigurationSection connectionStrings =
config.GetSection("connectionStrings");
if (connectionStrings != null)
// Only decrypt the section if it is protected
if (connectionStrings.SectionInformation.IsProtected)
{
// Decrypt the <connectionStrings> section
connectionStrings.SectionInformation.UnprotectSection();
config.Save();
// Refresh the Web.config display
DisplayWebConfig();
}
}
Il codice usato nei due gestori eventi è quasi identico. Entrambi iniziano ottenendo informazioni sul file dell'applicazione Web.config
corrente tramite ilWebConfigurationManager
metodo della classe .OpenWebConfiguration
Questo metodo restituisce il file di configurazione Web per il percorso virtuale specificato. Successivamente, la Web.config
sezione s del <connectionStrings>
file è accessibile tramite il Configuration
metodo della GetSection(sectionName)
classe , che restituisce un ConfigurationSection
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 SectionInformation
proprietà della IsProtected
proprietà . Inoltre, la sezione può essere crittografata o decrittografata tramite i metodi e UnprotectSection
della SectionInformation
proprietà ProtectSection(provider)
.
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 ProtectSection(provider)
metodo o UnprotectSection
, è necessario chiamare il metodo dell'oggetto Configuration
Save
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).
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 HttpRequestValidationException
oggetto , che visualizza il messaggio, un valore potenzialmente pericoloso Request.Form
rilevato 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 @Page
direttiva . 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. Al postback, si accederà al file di configurazione e alla relativa <connectionStrings>
sezione crittografata usando il provider DPAPI. Il controllo TextBox viene quindi aggiornato per visualizzare il nuovo Web.config
contenuto. Come illustrato nella figura 4, le <connectionStrings>
informazioni sono ora crittografate.
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>AQAAANCMnd8BFdERjHoAwE/...zChw==</CipherValue>
</CipherData>
</EncryptedData>
</connectionStrings>
Nota
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 stringa di connessione da Web.config
, dal codice scritto, da un controllo SqlDataSource o dal codice generato automaticamente dagli oggetti TableAdapter nei set di dati tipizzato, viene decrittografato 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 illustrato nella figura 5, l'esercitazione funziona esattamente come ci si aspetterebbe, a indicare che le informazioni stringa di connessione crittografate vengono decrittografate automaticamente dalla pagina ASP.NET.
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 relativa rappresentazione in testo normale, <connectionStrings>
fare clic sul pulsante Decrittografa stringhe di connessione. Al postback dovrebbero essere visualizzati i stringa di connessione in Web.config
testo normale. 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, è stato 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
sezione è la sezione di configurazione per crittografare (ad esempio connectionStrings), il physical_directory è il percorso fisico completo della directory radice dell'applicazione Web e il provider è il nome del provider di configurazione protetto da usare , ad esempio 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_CS"
-prov "DataProtectionConfigurationProvider"
Analogamente, lo strumento da aspnet_regiis.exe
riga di comando 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
Nota
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 SELECT
query , INSERT
, UPDATE
o 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 ASP.NET applicazioni in Microsoft Internet Information Server (IIS), ASP.NET applicazioni in genere presuppongono l'identità di
domainName``\MachineName
odomainName``\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 autenticazione di Windows il stringa di connessione è gratuito da un nome utente e una password e se il server Web e il server di database si trovano in due computer diversi, le credenziali non vengono inviate in rete in testo normale. 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. Il stringa di connessione in Web.config
per le esercitazioni è stato:
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 usato autenticazione di Windows. In alcuni stringa di connessione il termine Trusted Connection=Yes o Integrated Security=SSPI viene usato invece di Integrated Security=True, ma tutti e tre indicano l'uso di autenticazione di Windows.
Nell'esempio seguente viene illustrato un stringa di connessione che usa l'autenticazione SQL. $CREDENTIAL_PLACEHOLDER$
è un segnaposto per la coppia chiave-valore della password. Si noti che le credenziali sono incorporate all'interno del stringa di connessione:
Server=serverName; Database=Northwind; uid=userID; $CREDENTIAL_PLACEHOLDER$
Si supponga 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.
Nota
Per altre informazioni sui diversi tipi di autenticazione disponibili in SQL Server, vedere Building Secure ASP.NET Applications: Authentication, Authorization e Secure Communication. Per altri stringa di connessione esempi che illustrano le differenze tra la sintassi di autenticazione di Windows e SQL, vedere ConnectionStrings.com.
Riepilogo
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:
- Compilazione di un'applicazione sicura ASP.NET: autenticazione, autorizzazione e comunicazione sicura
- Crittografia delle informazioni di configurazione nelle applicazioni ASP.NET 2.0
- Crittografia dei
Web.config
valori in ASP.NET 2.0 - Procedura: Crittografare le sezioni di configurazione in ASP.NET 2.0 usando DPAPI
- Procedura: crittografare le sezioni di configurazione in ASP.NET 2.0 utilizzando RSA
- API di configurazione in .NET 2.0
- Protezione dei dati di Windows
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 all'indirizzo mitchell@4GuysFromRolla.com. o tramite il suo blog, che può essere trovato all'indirizzo http://ScottOnWriting.NET.
Grazie speciale a
Questa serie di esercitazioni è stata esaminata da molti revisori utili. I revisori principali per questa esercitazione erano Teresa Murphy e Randy Schmidt. Si è interessati a esaminare i prossimi articoli MSDN? In tal caso, rilasciarmi una riga in mitchell@4GuysFromRolla.com.