Procédure : Utiliser l'authentification par formulaires avec SQL Server 2000
Sur cette page
Objectifs
S'applique à
Résumé
Points à connaître
Créer une application Web avec une page de connexion
Configurer l'application Web en vue d'une authentification par formulaires
Développer des fonctions pour générer des valeurs de hachage et salt
Créer une base de données de comptes d'utilisateurs
Utiliser ADO.NET pour stocker des informations de compte dans la base de données
Authentifier des informations d'identification d'utilisateur auprès de la base de données
Tester l'application
Ressources supplémentaires
Objectifs
Ce module vous permet d'effectuer les opérations suivantes :
-
créer une application Web qui utilise l'authentification par formulaires afin d'authentifier les utilisateurs auprès de SQL Server ;
-
stocker et valider de façon sécurisée les informations d'identification des utilisateurs à l'aide du hachage de mot de passe.
S'applique à
Ce module s'applique aux produits et technologies suivants :
-
Microsoft Windows® XP ou Windows 2000 Server (avec le Service Pack 3) et systèmes d'exploitation ultérieurs
-
Microsoft.NET Framework version 1.0 (avec le Service Pack 2) et versions ultérieures
-
Microsoft Visual Studio® 1.0 .NET et versions ultérieures
-
Microsoft Visual C#® .NET
-
SQL Server 2000 (avec le Service Pack 2) et versions ultérieures
Résumé
L'authentification par formulaires ASP.NET permet aux utilisateurs de s'identifier en entrant des informations d'identification (un nom d'utilisateur et un mot de passe) dans un formulaire Web. Lors de la réception de ces informations, l'application Web peut authentifier l'utilisateur en comparant les informations d'identification avec une source de données.
Ce module décrit comment stocker de façon sécurisée les informations d'identification des utilisateurs dans Microsoft® SQL Server? à l'aide du hachage de mot de passe et comment authentifier les utilisateurs auprès d'une base de données de comptes incluse dans SQL Server.
Points à connaître
Le stockage sécurisé des informations d'identification des utilisateurs fait appel à deux concepts clés :
-
Stockage de hachages (digests) de mots de passe. Pour des raisons de sécurité, les mots de passe ne doivent pas figurer en texte brut dans la base de données. Ce module décrit comment créer et stocker un hachage unidirectionnel du mot de passe de l'utilisateur plutôt que le mot de passe lui-même. Cette méthode est préférable au stockage d'une version cryptée du mot de passe de l'utilisateur, afin d'éviter les principaux problèmes de gestion associés aux techniques de cryptage.
Pour bénéficier d'une sécurité accrue et atténuer les risques liés aux attaques de dictionnaire, l'approche décrite dans ce module associe une valeur salt (nombre aléatoire) au mot de passe, avant la création du hachage de mot de passe.Important : si l'utilisateur oublie le mot de passe, celui-ci ne peut toutefois pas être récupéré car les mots de passe ne sont pas stockés dans la base de données. Par conséquent, votre application doit utiliser des indications de mot de passe et les stocker avec le hachage de mot de passe dans la base de données.
-
Validation des entrées de l'utilisateur. Lorsque les entrées de l'utilisateur sont transférées aux commandes SQL, sous forme d'opérateurs sur chaîne dans des instructions de comparaison ou de critères spéciaux, vous devez être extrêmement vigilant lors de la validation. Vous devez en effet vous assurer que les commandes qui en résultent ne contiennent aucune erreur de syntaxe et qu'aucun pirate ne puisse faire en sorte que votre application exécute des commandes SQL arbitraires. La validation du nom d'utilisateur fourni lors d'un processus de connexion se révèle indispensable, car le modèle de sécurité de votre application dépend entièrement de sa faculté à authentifier correctement et de manière sécurisée les utilisateurs.
Pour plus d'informations sur la validation des entrées utilisateur pour les commandes SQL, consultez la section « Injections de code SQL » dans le Module 12, « Sécurité de l'accès aux données ».
Créer une application Web avec une page de connexion
Cette procédure permet de créer une application Web Visual C# simple qui contient une page de connexion offrant la possibilité d'entrer un nom d'utilisateur et un mot de passe.
-
Pour créer une application Web avec une page de connexion
-
Démarrez Visual Studio .NET et créez une application Web ASP.NET Visual C# nommée FormsAuthSQL.
-
Utilisez l'Explorateur de solutions pour renommer WebForm1.aspx en Logon.aspx.
-
Ajoutez à Logon.aspx les contrôles mentionnés dans le tableau 1 pour créer un formulaire de connexion simple.
Tableau 1 : Contrôles Logon.aspx
Type de contrôle
Texte
ID
Étiquette
Nom d'utilisateur :
-
Étiquette
Mot de passe
-
Zone de texte
-
txtUserName
Zone de texte
-
txtPassword
Bouton
Inscription
btnRegister
Bouton
Connexion
btnLogon
Étiquette
-
lblMessage
Votre page Web doit ressembler à celle illustrée dans la figure 1.
Figure 1
Formulaire Web de page de connexion -
Attribuez la valeur Password à la propriété TextMode du contrôle de zone de texte txtPassword.
-
Configurer l'application Web en vue d'une authentification par formulaires
Cette procédure permet de modifier le fichier Web.config afin de configurer l'application en vue d'une authentification par formulaires.
-
Pour configurer l'application Web en vue d'une authentification par formulaires
-
Utilisez l'Explorateur de solutions pour ouvrir le fichier Web.config.
-
Recherchez l'élément <authentication> et remplacez la valeur de l'attribut mode par Forms.
-
Ajoutez l'élément <forms> suivant en tant qu'enfant de l'élément <authentication> et définissez les attributs loginUrl, name, timeout et path comme illustré ci-dessous.
<authentication mode="Forms"> <forms loginUrl="logon.aspx" name="sqlAuthCookie" timeout="60" path="/"> </forms> </authentication>
-
Ajoutez l'élément <authorization> suivant sous l'élément <authentication>. Ainsi, seuls les utilisateurs authentifiés pourront accéder à l'application. L'attribut loginUrl défini précédemment pour l'élément <authentication> redirigera les demandes non authentifiées vers la page logon.aspx.
<authorization> <deny users="?" /> <allow users="*" /> </authorization>
-
Développer des fonctions pour générer des valeurs de hachage et salt
Cette procédure ajoute deux méthodes d'utilitaire à votre application Web : une pour générer une valeur salt (nombre aléatoire) aléatoire, et une autre pour créer un hachage à partir d'un mot de passe et d'une valeur salt fournis.
-
Pour développer des fonctions afin de générer une valeur de hachage et salt
-
Ouvrez Logon.aspx.cs et ajoutez les instructions using suivantes en haut du fichier, sous les instructions using existantes.
using System.Security.Cryptography; using System.Web.Security;
-
Ajoutez la méthode statique suivante à la classe WebForm1 pour générer une valeur salt et renvoyer celle-ci sous la forme d'une chaîne codée en base 64.
private static string CreateSalt(int size) { // Générer un numéro aléatoire crypté à l'aide du // fournisseur de services cryptographiques. RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider(); byte[] buff = new byte[size]; rng.GetBytes(buff); // Renvoyer une représentation de chaîne en Base64 du numéro aléatoire. return Convert.ToBase64String(buff); } -
Ajoutez la méthode statique suivante pour créer une valeur de hachage à partir d'un mot de passe et d'une valeur salt fournis.
private static string CreatePasswordHash(string pwd, string salt) { string saltAndPwd = String.Concat(pwd, salt); string hashedPwd = FormsAuthentication.HashPasswordForStoringInConfigFile( saltAndPwd, "SHA1"); return hashedPwd; }
-
Créer une base de données de comptes d'utilisateurs
Cette procédure permet de créer dans SQL Server une base de données de comptes d'utilisateurs qui contient une table d'utilisateurs et une procédure stockée destinée à interroger la base de données d'utilisateurs.
-
Pour créer une base de données de comptes d'utilisateurs
-
Dans le groupe de programmes Microsoft SQL Server, choisissez Analyseur de requêtes et établissez une connexion à votre serveur SQL Server local.
-
Entrez le script SQL suivant. Notez que vous devez remplacer « LocalMachine » par le nom de votre ordinateur vers la fin du script.
USE master GO -- Créer une base de données destinée aux informations de sécurité. 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 -- Créer une procédure stockée pour inscrire les informations utilisateur. CREATE PROCEDURE RegisterUser @userName varchar(255), @passwordHash varchar(40), @salt varchar(10) AS INSERT INTO Users VALUES(@userName, @passwordHash, @salt) GO -- Créer une procédure stockée pour extraire les informations utilisateur. CREATE PROCEDURE LookupUser @userName varchar(255) AS SELECT PasswordHash, salt FROM Users WHERE UserName = @userName GO -- Ajouter une connexion pour le compte ASPNET local. -- Dans les instructions suivantes, remplacer LocalMachine par votre -- nom d'ordinateur local. exec sp_grantlogin [LocalMachine\ASPNET] -- Ajouter une connexion de base de données pour la base de données UserAccounts du compte ASPNET. exec sp_grantdbaccess [LocalMachine\ASPNET] -- Accorder des autorisations d'exécution aux utilisateurs stockés LookupUser et RegisterUser. procs grant execute on LookupUser to [LocalMachine\ASPNET] grant execute on RegisterUser to [LocalMachine\ASPNET] -
Exécutez la requête pour créer la base de données UserAccounts.
-
Quittez le gestionnaire de requêtes.
-
Utiliser ADO.NET pour stocker des informations de compte dans la base de données
Cette procédure permet de modifier le code d'application Web pour stocker dans la base de données le nom d'utilisateur fourni, ainsi que les valeurs salt et de hachage du mot de passe générées.
-
Pour utiliser ADO.NET afin de stocker des informations de compte dans la base de données
-
Revenez dans Visual Studio .NET et double-cliquez sur le bouton Inscription dans le formulaire Web afin de créer un gestionnaire d'événements de clic de bouton.
-
Ajoutez le code suivant à la méthode.
string salt = CreateSalt(5); string passwordHash = CreatePasswordHash(txtPassword.Text,salt); try { StoreAccountDetails( txtUserName.Text, passwordHash, salt); } catch(Exception ex) { lblMessage.Text = ex.Message; } -
Ajoutez l'instruction using suivante en haut du fichier, sous les instructions using existantes.
using System.Data.SqlClient;
-
Ajoutez la méthode d'utilitaire StoreAccountDetails à l'aide du code suivant. Ce code utilise ADO.NET pour établir une connexion à la base de données UserAccounts et stocke le nom d'utilisateur fourni ainsi que les valeurs salt et de hachage du mot de passe dans la table Users.
private void StoreAccountDetails( string userName, string passwordHash, string salt ) { // Consulter la section " Comment utiliser DPAPI (magasin de l'ordinateur) à partir de ASP.NET " pour plus d'informations // sur le stockage sécurisé des chaînes de connexion. 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 permettant de vérifier les éventuelles violations de clés principales (nom de compte en double) // ou d'autres erreurs de base de données omis pour simplifier. throw new Exception("Exception liée à l'ajout d'un compte. " + ex.Message); } finally { conn.Close(); } }
-
Authentifier des informations d'identification d'utilisateur auprès de la base de données
Cette procédure développe le code ADO.NET pour rechercher le nom d'utilisateur fourni dans la base de données et valider le mot de passe indiqué, en faisant correspondre les hachages de mot de passe.
Remarque : dans de nombreux scénarios d'authentification par formulaires dans lesquels vous utilisez une autorisation par rôle .NET, vous pouvez aussi extraire à ce stade à partir de la base de données les rôles auxquels l'utilisateur est associé. Ces rôles peuvent ensuite être utilisés pour créer un objet GenericPrincipal susceptible d'être associé à des demandes Web authentifiées, en vue d'une autorisation .NET.
Pour plus d'informations sur la construction d'un ticket d'authentification par formulaires comprenant des informations relatives au rôle d'un utilisateur, consultez la section « Procédure : Créer des objets GenericPincipal avec l'authentification par formulaires » dans la section Référence de ce guide.
-
Pour authentifier des informations d'identité d'utilisateur auprès de la base de données
-
Revenez au fichier Logon.aspx.cs et ajoutez la méthode utile privée VerifyPassword comme illustré dans le code suivant.
private bool VerifyPassword(string suppliedUserName, string suppliedPassword ) { bool passwordMatch = false; // Récupérer la valeur salt et le mot de passe de la base de données en fonction du nom d'utilisateur. // Voir "Procédure : Utiliser DPAPI (magasin de l'ordinateur) à partir de ASP.NET", "Procédure : Utiliser DPAPI // (magasin d'utilisateurs) à partir de Microsoft Enterprise Services" et "Procédure : Créer une bibliothèque // DPAPI" pour plus d'informations sur l'utilisation de DPAPI dans le but de stocker // des chaînes de connexion de façon sécurisée.. 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(); // Avancer jusqu'à la ligne unique // Renvoyer des paramètres de sortie à partir du flux de données obtenu. string dbPasswordHash = reader.GetString(0); string salt = reader.GetString(1); reader.Close(); // Prendre à présent la valeur salt et le mot de passe entré par l'utilisateur // afin de les concaténer.. string passwordAndSalt = String.Concat(suppliedPassword, salt); // Hacher ces éléments. string hashedPasswordAndSalt = FormsAuthentication.HashPasswordForStoringInConfigFile( passwordAndSalt, "SHA1"); // Vérifier ces éléments. passwordMatch = hashedPasswordAndSalt.Equals(dbPasswordHash); } catch (Exception ex) { throw new Exception("Exception lors de la vérification du mot de passe. " + ex.Message); } finally { conn.Close(); } return passwordMatch; }
-
Tester l'application
Cette procédure permet de tester l'application. Vous devez d'abord inscrire un utilisateur pour ajouter un nom d'utilisateur ainsi qu'une valeur salt et de hachage du mot de passe à la table Users de la base de données UserAccounts. Vous devez ensuite connecter ce même utilisateur pour vous assurer du bon fonctionnement des routines de vérification du mot de passe.
-
Pour tester l'application
-
Revenez au formulaire de connexion et double-cliquez sur le bouton Connexion pour créer un gestionnaire d'événements de clic de bouton.
-
Ajoutez le code suivant au gestionnaire d'événements de clic de bouton Connexion pour appeler la méthode VerifyPassword et afficher un message défini en fonction de la validité du nom d'utilisateur et du mot de passe fournis.
bool passwordVerified = false; try { passwordVerified = VerifyPassword(txtUserName.Text,txtPassword.Text); } catch(Exception ex) { lblMessage.Text = ex.Message; return; } if (passwordVerified == true ) { // L'utilisateur est authentifié. // À ce stade, un ticket d'authentification doit normalement être créé. // Ce ticket peut être utilisé ensuite pour générer un objet GenericPrincipal // dans le cadre d'une autorisation .NET. // Pour plus d'informations, consultez la section "Procédure : Créer des objets GenericPrincipal // avec l'authentification par formulaires". lblMessage.Text = "Connexion réussie : l'utilisateur est authentifié."; } else { lblMessage.Text = "Nom d'utilisateur ou mot de passe non valide"; } -
Dans le menu Générer, choisissez Générer la solution.
-
Dans l'Explorateur de solutions, cliquez avec le bouton droit sur logon.aspx et cliquez sur Afficher dans le navigateur.
-
Entrez un nom d'utilisateur et un mot de passe, puis cliquez sur Inscription.
-
Utilisez SQL Server Enterprise Manager pour afficher le contenu de la table Users. Vous devez utiliser une nouvelle ligne pour le nouveau nom d'utilisateur avec un hachage de mot de passe généré.
-
Revenez à la page Web de connexion, entrez de nouveau le mot de passe et cliquez sur Connexion. Le message « Connexion réussie : l'utilisateur est authentifié » doit apparaître.
-
Entrez à présent un mot de passe non valide (en conservant le même nom d'utilisateur). Le message « Nom d'utilisateur ou mot de passe non valide » doit s'afficher.
-
Fermez Internet Explorer.
-
Ressources supplémentaires
Pour plus d'informations, consultez les documents suivants :
-
« Procédure : Utiliser DPAPI (magasin de l'ordinateur) à partir de ASP.NET »
-
« Procédure : Créer des objets GenericPincipal avec l'authentification par formulaires »
-
« Injections de code SQL » dans le Module 12, « Sécurité de l'accès aux données »