In questa paginaObiettiviIl modulo consente di: | • | Creare un'applicazione Web che utilizza l'autenticazione basata su moduli per autenticare gli utenti per SQL Server. | | • | Archiviare e convalidare le credenziali utente mediante gli hash delle password. |
Ambito di applicazioneLe informazioni contenute in questo modulo sono valide per i seguenti prodotti e tecnologie: | • | Microsoft Windows® XP o Windows 2000 Server con Service Pack 3 e sistemi operativi successivi | | • | Microsoft .NET Framework versione 1.0 con Service Pack 2 e versioni successive | | • | Microsoft Visual Studio® 1.0 .NET e versioni successive | | • | Microsoft Visual C#® .NET | | • | SQL Server 2000 con Service Pack 2 e versioni successive |
Utilizzo del moduloPer trarre il massimo vantaggio dal modulo: | • | È necessario aver acquisito esperienza nell'utilizzo di Visual C# .NET e Visual Studio .NET. | | • | È necessario aver acquisito esperienza nello sviluppo di applicazioni Web mediante l'utilizzo di ASP.NET. | | • | È necessario aver acquisito esperienza nell'utilizzo di SQL Server e nella creazione di tabelle SQL Server. | | • | È necessario aver acquisito esperienza nell'utilizzo di ADO.NET per accedere a SQL Server. | | • | Occorre poter accedere a un'istanza di SQL Server utilizzabile per verificare l'applicazione (non deve trattarsi di un sistema di produzione). | | • | Leggere il modulo 12 "Protezione dell'accesso ai dati" di questa guida. Vi sono incluse informazioni dettagliate sull'accesso protetto al database, sulla creazione e l'archiviazione dei valori hash delle password e sulla protezione dagli attacchi mediante inserimento di codice SQL non autorizzato. | | • | Leggere "Procedura : Utilizzo dell'interfaccia DPAPI (archivio del computer) da ASP.NET". Vi sono incluse informazioni dettagliate sulla modalità di utilizzo di DPAPI per memorizzare in modalità protetta le stringhe di connessione a SQL Server. | | • | Leggere "Procedura : Creazione di oggetti GenericPrincipal mediante l'autenticazione basata su moduli". Vi sono incluse informazioni dettagliate sulla costruzione di un ticket di autenticazione basata su moduli che include i dettagli sui ruoli di un utente. |
RiepilogoL'autenticazione basata su moduli di ASP.NET consente agli utenti di identificarsi immettendo le credenziali (nome utente e password) in un modulo Web. Quando l'applicazione Web riceve queste credenziali, può autenticare l'utente controllando la combinazione delle credenziali rispetto a un'origine dati. In questo modulo viene descritto come archiviare le credenziali utente in modalità protetta in Microsoft® SQL Server™ utilizzando l'hash delle password, nonché come autenticare gli utenti rispetto a un database di account contenuto in SQL Server. Conoscenze necessarieIn relazione all'archiviazione in modalità protetta delle credenziali utente occorre considerare due concetti chiave: | • | Archiviazione di digest di password. Per motivi di sicurezza, è consigliabile non archiviare le password in formato testo non crittografato nel database. In questo modulo viene descritto come creare e archiviare un hash unidirezionale della password di un utente anziché la password stessa. Questo approccio è preferibile all'archiviazione di una versione crittografata della password dell'utente in quanto consente di evitare i problemi di gestione della chiave associati alle tecniche di crittografia. Per assicurare una maggiore protezione e ridurre il rischio associato agli attacchi al dizionario, nel metodo descritto in questo modulo viene assegnato alla password un valore salt, ovvero un numero casuale generato a livello di crittografia, prima di creare il relativo hash. Importante: l'unico svantaggio, quando non si archiviano le password nel database, è rappresentato dal fatto che, se l'utente dimentica la password, non è possibile recuperarla. E’ quindi consigliabile che l'applicazione utilizzi i suggerimenti per le password e li archivi nel digest di password all'interno del database. | | • | Convalida dell'input dell'utente. Quando l'input dell'utente viene passato ai comandi SQL, ad esempio come rappresentazione formale di stringa nelle istruzioni di confronto o di corrispondenza dei modelli, è necessario prestare particolare attenzione alla convalida dell'input, Questo per verificare che i comandi risultanti non contengano errori di sintassi e anche per impedire che un pirata informatico possa causare l'esecuzione non autorizzata di comandi SQL nell'applicazione. La convalida del nome utente specificato durante un processo di accesso è particolarmente importante, in quanto il modello di protezione dell'applicazione dipende completamente dalla possibilità di autenticare gli utenti in modo corretto e sicuro. Per ulteriori informazioni sulla convalida dell'input dell'utente per i comandi SQL e le funzioni di convalida, vedere "Attacchi mediante inserimento di codice SQL non autorizzato" nel modulo 12, "Protezione dell'accesso ai dati". |
Creazione di un'applicazione Web con una pagina di accessoQuesta procedura consente di creare una semplice applicazione Web Visual C# contenente una pagina di accesso in cui l'utente può inserire il nome utente e la password. | • | Per creare un'applicazione Web con una pagina di accesso 1. | Avviare Visual Studio .NET e creare una nuova applicazione Web ASP.NET Visual C# denominata FormsAuthSQL. | 2. | Utilizzare Esplora soluzioni per rinominare WebForm1.aspx come Logon.aspx. | 3. | Aggiungere a Logon.aspx i controlli elencati nella tabella 1 per creare un semplice modulo di accesso. Tabella 1: Controlli di Logon.aspx Etichetta | Nome utente | - | Etichetta | Password | - | Casella di testo | - | txtUserName | Casella di testo | - | txtPassword | Pulsante | Registrati | btnRegister | Pulsante | Accedi | btnLogon | Etichetta | - | lblMessage |
La pagina Web sarà simile a quella illustrata nella figura 1.  Figura 1 Modulo Web della pagina di accesso | 4. | Impostare la proprietà TextMode di txtPassword su Password. |
|
Configurazione dell'applicazione Web per l'autenticazione basata su moduliQuesta procedura consente di modificare il file web.config dell'applicazione in modo da configurare quest'ultima per l'autenticazione basata su moduli. | • | Per configurare l'applicazione Web per l'autenticazione basata su moduli 1. | Utilizzare Esplora soluzioni per aprire il file web.config. | 2. | Individuare l'elemento <authentication> e modificare l'attributo mode impostandolo su Forms. | 3. | Aggiungere l'elemento <forms> che segue come figlio dell'elemento <authentication> e impostare gli attributi loginUrl, name, timeout e path nel modo seguente:
<authentication mode="Forms">
<forms loginUrl="logon.aspx" name="sqlAuthCookie" timeout="60" path="/">
</forms>
</authentication>
| 4. | Aggiungere l'elemento <authorization> riportato di seguito sotto l'elemento <authentication>. In questo modo, l'accesso all'applicazione verrà consentito solo agli utenti autenticati. L'attributo loginUrl dell'elemento <authentication>, definito in precedenza, reindirizzerà le richieste non autenticate alla pagina logon.aspx.
<authorization>
<deny users="?" />
<allow users="*" />
</authorization>
|
|
Sviluppo di funzioni per generare un hash e un valore saltQuesta procedura consente di aggiungere due metodi all'applicazione, uno per generare un valore salt casuale e uno per creare un hash in base alla password specificata e al valore salt. | • | Per sviluppare funzioni per generare un hash e un valore salt 1. | Aprire Logon.aspx.cs e aggiungere le istruzioni using riportate di seguito all'inizio del file, sotto le istruzioni using esistenti.
using System.Security.Cryptography;
using System.Web.Security;
| 2. | Aggiungere alla classe WebForm1 il metodo statico riportato di seguito per generare un valore salt casuale e restituirlo come stringa codificata Base 64.
private static string CreateSalt(int size)
{
// Generate a cryptographic random number using the cryptographic
// service provider
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
byte[] buff = new byte[size];
rng.GetBytes(buff);
// Return a Base64 string representation of the random number
return Convert.ToBase64String(buff);
}
| 3. | Aggiungere il metodo statico riportato di seguito per generare un valore hash in base alla password specificata e al valore salt.
private static string CreatePasswordHash(string pwd, string salt)
{
string saltAndPwd = String.Concat(pwd, salt);
string hashedPwd =
FormsAuthentication.HashPasswordForStoringInConfigFile(
saltAndPwd, "SHA1");
return hashedPwd;
}
|
|
Creazione di un database di account utenteQuesta procedura consente di creare in SQL Server un nuovo database di account utente contenente contiene una singola tabella degli utenti e una stored procedure utilizzata per eseguire query al database utente. | • | Per creare un database di account utente 1. | Scegliere Microsoft SQL Server dal menu Programmi, fare clic su Query Analyzer, quindi connettersi al computer SQL Server locale. | 2. | Immettere lo script SQL riportato di seguito. Tenere presente che, alla fine dello script, è necessario sostituire "LocalMachine" con il nome del computer in uso.
USE master
GO
-- create a database for the security information
IF EXISTS (SELECT * FROM master..sysdatabases WHERE
name = 'UserAccounts')
DROP DATABASE UserAccounts
GO
CREATE DATABASE UserAccounts
GO
USE UserAccounts
GO
CREATE TABLE [Users] (
[UserName] [varchar] (255) NOT NULL ,
[PasswordHash] [varchar] (40) NOT NULL ,
[salt] [varchar] (10) NOT NULL,
CONSTRAINT [PK_Users] PRIMARY KEY CLUSTERED
(
[UserName]
) ON [PRIMARY]
) ON [PRIMARY]
GO
-- create stored procedure to register user details
CREATE PROCEDURE RegisterUser
@userName varchar(255),
@passwordHash varchar(40),
@salt varchar(10)
AS
INSERT INTO Users VALUES(@userName, @passwordHash, @salt)
GO
-- create stored procedure to retrieve user details
CREATE PROCEDURE LookupUser
@userName varchar(255)
AS
SELECT PasswordHash, salt
FROM Users
WHERE UserName = @userName
GO
-- Add a login for the local ASPNET account
-- In the following statements, replace LocalMachine with your
-- local machine name
exec sp_grantlogin [LocalMachine\ASPNET]
-- Add a database login for the UserAccounts database for the
ASPNET account
exec sp_grantdbaccess [LocalMachine\ASPNET]
-- Grant execute permissions to the LookupUser and RegisterUser stored
procs
grant execute on LookupUser to [LocalMachine\ASPNET]
grant execute on RegisterUser to [LocalMachine\ASPNET]
| 3. | Eseguire la query per creare il database UserAccounts. | 4. | Chiudere Query Analyzer. |
|
Utilizzo di ADO .NET per archiviare i dettagli degli account nel databaseQuesta procedura consente di modificare il codice dell'applicazione Web per archiviare il nome utente specificato, l'hash di password generato e il valore salt nel database. | • | Per utilizzare ADO .NET per archiviare i dettagli degli account nel database 1. | Tornare a Visual Studio .NET e fare doppio clic sul pulsante Registrati nel modulo Web per creare un gestore eventi ButtonClick. | 2. | Aggiungere al metodo il seguente codice:
string salt = CreateSalt(5);
string passwordHash = CreatePasswordHash(txtPassword.Text,salt);
try
{
StoreAccountDetails( txtUserName.Text, passwordHash, salt);
}
catch(Exception ex)
{
lblMessage.Text = ex.Message;
}
| 3. | Aggiungere l'istruzione using riportata di seguito all'inizio del file, sotto le istruzioni using esistenti.
using System.Data.SqlClient;
| 4. | Aggiungere il metodo StoreAccountDetails mediante il codice riportato di seguito, che utilizza ADO .NET per eseguire la connessione al database UserAccounts e consente di archiviare il nome utente, l'hash di password e il valore salt nella tabella Users.
private void StoreAccountDetails( string userName,
string passwordHash,
string salt )
{
// See "How To Use DPAPI (Machine Store) from ASP.NET" for information
// about securely storing connection strings.
SqlConnection conn = new SqlConnection( "Server=(local);" +
"Integrated Security=SSPI;" +
"database=UserAccounts");
SqlCommand cmd = new SqlCommand("RegisterUser", conn );
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter sqlParam = null;
sqlParam = cmd.Parameters.Add("@userName", SqlDbType.VarChar, 255);
sqlParam.Value = userName;
sqlParam = cmd.Parameters.Add("@passwordHash ", SqlDbType.VarChar, 40);
sqlParam.Value = passwordHash;
sqlParam = cmd.Parameters.Add("@salt", SqlDbType.VarChar, 10);
sqlParam.Value = salt;
try
{
conn.Open();
cmd.ExecuteNonQuery();
}
catch( Exception ex )
{
// Code to check for primary key violation (duplicate account name)
// or other database errors omitted for clarity
throw new Exception("Exception adding account. " + ex.Message);
}
finally
{
conn.Close();
}
}
|
|
Autenticazione delle credenziali utente rispetto al databaseQuesta procedura consente di sviluppare un codice ADO .NET per eseguire la ricerca del nome utente specificato nel database e convalidare la password indicata, in base alla corrispondenza degli hash di password. Nota: a questo punto, in vari scenari di autenticazione basata su moduli in cui si utilizza l'autorizzazione .NET basata sui ruoli, è possibile anche recuperare dal database i ruoli ai quali l’utente appartiene. Tali ruoli possono essere poi utilizzati allo scopo di generare un oggetto GenericPrincipal da associare alle richieste Web autenticate per motivi di autorizzazione .NET. Per ulteriori informazioni sulla creazione di un ticket di autenticazione basata su moduli che include i dettagli sui ruoli di un utente, vedere "Procedura – Creazione di oggetti GenericPrincipal mediante l'autenticazione basata su moduli" nella sezione relativa ai riferimenti di questa guida. | • | Per autenticare le credenziali utente rispetto al database 1. | Tornare a Logon.aspx.cs e aggiungere il metodo dell'helper privato VerifyPassword come indicato nel seguente codice:
private bool VerifyPassword(string suppliedUserName,
string suppliedPassword )
{
bool passwordMatch = false;
// Get the salt and pwd from the database based on the user name.
// See "How To: Use DPAPI (Machine Store) from ASP.NET," "How To: Use
DPAPI
// (User Store) from Enterprise Services," and "How To: Create a DPAPI
// Library" for more information about how to use DPAPI to securely
store
// connection strings.
SqlConnection conn = new SqlConnection( "Server=(local);" +
"Integrated Security=SSPI;" +
"database=UserAccounts");
SqlCommand cmd = new SqlCommand( "LookupUser", conn );
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter sqlParam = cmd.Parameters.Add("@userName",
SqlDbType.VarChar, 255);
sqlParam.Value = suppliedUserName;
try
{
conn.Open();
SqlDataReader reader = cmd.ExecuteReader();
reader.Read(); // Advance to the one and only row
// Return output parameters from returned data stream
string dbPasswordHash = reader.GetString(0);
string salt = reader.GetString(1);
reader.Close();
// Now take the salt and the password entered by the user
// and concatenate them together.
string passwordAndSalt = String.Concat(suppliedPassword, salt);
// Now hash them
string hashedPasswordAndSalt =
FormsAuthentication.HashPasswordForStoringInConfigFile(
passwordAndSalt, "SHA1");
// Now verify them.
passwordMatch = hashedPasswordAndSalt.Equals(dbPasswordHash);
}
catch (Exception ex)
{
throw new Exception("Execption verifying password. " + ex.Message);
}
finally
{
conn.Close();
}
return passwordMatch;
}
|
|
Test dell'applicazioneQuesta procedura consente di eseguire il test dell'applicazione. Eseguire la registrazione di un utente, che porterà all’aggiunta del nome utente, dell'hash di password e del valore salt alla tabella Users nel database UserAccounts. Quindi si dovrà eseguire l'accesso dello stesso utente per assicurare il corretto funzionamento delle routine di verifica della password. | • | Per eseguire il test dell'applicazione 1. | Tornare al modulo di accesso e fare doppio clic sul pulsante Accedi per creare un gestore dell’evento ButtonClick. | 2. | Aggiungere il codice riportato di seguito al gestore evento ButtonClick Accedi per chiamare il metodo VerifyPassword e visualizzare un messaggio in cui viene indicato se il nome utente e la password specificati sono validi o meno.
bool passwordVerified = false;
try
{
passwordVerified = VerifyPassword(txtUserName.Text,txtPassword.Text);
}
catch(Exception ex)
{
lblMessage.Text = ex.Message;
return;
}
if (passwordVerified == true )
{
// The user is authenticated
// At this point, an authentication ticket is normally created
// This can subsequently be used to generate a GenericPrincipal
// object for .NET authorization purposes
// For details, see "How To: Use Forms authentication with
GenericPrincipal
// objects
lblMessage.Text = "Logon successful: User is authenticated";
}
else
{
lblMessage.Text = "Invalid username or password";
}
| 3. | Scegliere Genera soluzione dal menu Genera. | 4. | In Esplora soluzioni fare clic con il pulsante destro del mouse su logon.aspx, quindi scegliere Visualizza nel browser. | 5. | Immettere un nome utente e una password, quindi fare clic su Registrati. | 6. | Utilizzare SQL Server Enterprise Manager per visualizzare il contenuto della tabella Users. Verrà visualizzata una nuova riga per il nuovo nome utente insieme all'hash di password generato. | 7. | Tornare alla pagina Web di accesso, immettere nuovamente la password, quindi fare clic su Accedi. Verrà visualizzato il messaggio "Logon successful: User is authenticated". | 8. | A questo punto immettere una password non valida, lasciando invariato il nome utente. Verrà visualizzato il messaggio "Invalid username or password". | 9. | Chiudere Internet Explorer. |
|
Altre risorsePer ulteriori informazioni, vedere le seguenti risorse:
| |