Vorgehensweise: Verwenden der Formularauthentifizierung mit SQL Server 2000

* * *

Auf dieser Seite

Zielsetzung Zielsetzung
Betrifft Betrifft
Verwendung dieses Moduls Verwendung dieses Moduls
Zusammenfassung Zusammenfassung
Benötigte Kenntnisse Benötigte Kenntnisse
Erstellen einer Webanwendung mit einer Anmeldeseite Erstellen einer Webanwendung mit einer Anmeldeseite
Konfigurieren der Webanwendung für die Formularauthentifizierung Konfigurieren der Webanwendung für die Formularauthentifizierung
Entwickeln von Funktionen zum Erzeugen eines Hashes und eines Salt-Wertes Entwickeln von Funktionen zum Erzeugen eines Hashes und eines Salt-Wertes
Erstellen einer Benutzerkontendatenbank Erstellen einer Benutzerkontendatenbank
Verwenden von ADO.NET zum Speichern von Kontodetails in der Datenbank Verwenden von ADO.NET zum Speichern von Kontodetails in der Datenbank
Authentifizieren von Benutzeranmeldeinformationen anhand der Datenbank Authentifizieren von Benutzeranmeldeinformationen anhand der Datenbank
Testen der Anwendung Testen der Anwendung
Weitere Ressourcen Weitere Ressourcen

Zielsetzung

Themenbereiche:

  • Erstellen einer Webanwendung, die Formularauthentifizierung verwendet, um Benutzer für den SQL Server zu authentifizieren

  • Speichern und Überprüfen von Benutzeranmeldeinformationen durch sichere Verwendung von Kennworthashes

 

Betrifft

Die Informationen in diesem Modul gelten für folgende Produkte und Technologien:

  • Microsoft Windows® XP oder Windows 2000 Server (mit Service Pack 3) und höhere Betriebssysteme

  • Microsoft .NET Framework Version 1.0 (mit Service Pack 2) und höhere Versionen

  • Microsoft Visual Studio® 1.0 .NET und höhere Versionen

  • Microsoft Visual C#® .NET

  • SQL Server 2000 (mit Service Pack 2) und höhere Versionen

 

Verwendung dieses Moduls

Empfehlungen für eine erfolgreiche Arbeit mit diesem Modul:

  • Sie müssen über Erfahrung in Visual C# .NET und Visual Studio .NET verfügen.

  • Sie sollten über Erfahrung in der Entwicklung von Webanwendungen mithilfe von ASP.NET verfügen.

  • Sie sollten über Erfahrung in der Verwendung von SQL Server und in der Erstellung von SQL Server-Tabellen verfügen.

  • Sie sollten über Erfahrung in der Verwendung von ADO.NET zum Zugriff auf SQL Server verfügen.

  • Sie müssen auf eine Instanz von SQL Server zugreifen, die Sie zum Testen Ihrer Anwendung verwenden können. Hierbei sollte es sich nicht um ein Produktionssystem handeln.

  • Lesen Sie Modul 12 dieses Handbuches, "Datenzugriffssicherheit". Darin finden Sie Informationen über den sicheren Datenbankzugriff, zum Erstellen und Speichern von Kennworthashwerten und zum Schutz vor SQL Injection-Angriffen.

  • Lesen Sie "Vorgehensweise: Verwenden von DPAPI (Computerspeicher) von ASP.NET aus". Hier finden Sie Informationen zur Verwendung von DPAPI zum sicheren Speichern von SQL Server-Verbindungszeichenfolgen.

  • Lesen Sie "Vorgehensweise: Erstellen von GenericPrincipal-Objekten bei der Formularauthentifizierung". Hier erhalten Sie Informationen zur Erstellung eines Tickets für die Formularauthentifizierung, das Benutzerrollen enthält.

 

Zusammenfassung

Mit der von ASP.NET gebotenen Formularauthentifizierung können Benutzer sich identifizieren, indem sie Anmeldeinformationen (einen Benutzernamen und ein Kennwort) in ein Webformular eingeben. Beim Empfang dieser Anmeldeinformationen kann die Webanwendung den Benutzer authentifizieren, indem die Kombination aus Benutzername und Kennwort anhand einer Datenquelle geprüft wird.

In diesem Modul wird beschrieben, wie Benutzeranmeldeinformationen sicher mithilfe von Kennworthashes in Microsoft® SQL Server™ gespeichert werden und wie Benutzer anhand einer in SQL Server enthaltenen Kontendatenbank authentifiziert werden.

 

Benötigte Kenntnisse

Für die sichere Speicherung von Benutzeranmeldeinformationen gibt es zwei Schlüsselkonzepte:

  • Speichern von Kennwortdigests. Aus Sicherheitsgründen sollten Kennwörter in der Datenbank nicht im Klartext gespeichert werden. In diesem Modul wird erläutert, wie ein unidirektionaler Hash des Benutzerkennworts erstellt und anstelle des eigentlichen Kennworts gespeichert wird. Dieser Ansatz ist dem Speichern einer verschlüsselten Version des Benutzerkennworts vorzuziehen, um die mit Verschlüsselungstechniken einhergehenden primären Verwaltungsprobleme zu vermeiden.
    Für zusätzliche Sicherheit und um die Bedrohung zu vermindern, die von Verzeichnisangriffen ausgeht, wird bei dem in diesem Modul beschriebenen Ansatz vor der Erstellung des KennwortHashes ein Salt, d. h. eine kryptografisch erzeugte Zufallszahl, erstellt und mit dem Kennwort kombiniert.

    Wichtig: Die Tatsache, dass keine Kennwörter in der Datenbank gespeichert werden, hat den Nachteil, dass das Kennwort nicht wiederhergestellt werden kann, wenn der Benutzer es vergisst. Daher sollte die Anwendung mit "Eselsbrücken" arbeiten, die Hinweise auf das Kennwort geben, und diese zusammen mit dem Kennwortdigest in der Datenbank speichern.

  • Überprüfen der Benutzereingabe. Wenn die Benutzereingabe an SQL-Befehle übergeben wird, z. B. als Zeichenfolgenliteral in Vergleichs- oder Mustervergleichsanweisungen, sollte in jedem Fall dafür gesorgt werden, dass die Eingabe überprüft wird, um sicherzustellen, dass die sich ergebenden Befehle keine Syntaxfehler enthalten. Hiermit wird zudem sichergestellt, dass ein Hacker keine beliebigen SQL-Befehle in der Anwendung ausführen kann. Die Überprüfung des eingegebenen Benutzernamens während des Anmeldeverfahrens ist besonders wichtig, weil das gesamte Sicherheitsmodell der Anwendung ganz und gar von der Fähigkeit abhängt, Benutzer korrekt und sicher zu authentifizieren.

    Weitere Informationen zum Überprüfen der Benutzereingabe für SQL-Befehle und zu den Überprüfungsfunktionen finden Sie in Modul 12, "Datenzugriffssicherheit", im Abschnitt "SQL Injection-Angriffe".

 

Erstellen einer Webanwendung mit einer Anmeldeseite

In diesem Verfahren wird eine einfache Webanwendung mit Visual C# erstellt, die eine Anmeldeseite enthält, auf der der Benutzer einen Benutzernamen und ein Kennwort eingeben kann.

  • So erstellen Sie eine Webanwendung mit einer Anmeldeseite

    1. Starten Sie Visual Studio .NET und erstellen Sie eine neue Visual C# ASP.NET-Webanwendung mit Namen FormsAuthSQL.

    2. Benennen Sie WebForm1.aspx mithilfe des Projektmappen-Explorers in Logon.aspx um.

    3. Fügen Sie Logon.aspx die in Tabelle 1 aufgeführten Steuerelemente hinzu, um ein einfaches Anmeldeformular zu erstellen.

      Tabelle 1: Die Steuerelemente für Logon.aspx

      Typ des Steuerelements Text ID
      Bezeichnungsfeld Benutzername: -
      Bezeichnungsfeld Kennwort -
      Textfeld - txtUserName
      Textfeld - txtPassword
      Schaltfläche Registrieren btnRegister
      Schaltfläche Anmelden btnLogon
      Bezeichnungsfeld - lblMessage

      Die Webseite sollte ähnlich der in Abbildung 1 dargestellten aussehen.

      Webformular Anmeldeseite

      Abbildung 1
      Webformular Anmeldeseite

    4. Legen Sie die TextMode-Eigenschaft von txtPassword auf Kennwort fest.

 

Konfigurieren der Webanwendung für die Formularauthentifizierung

Mit dem folgenden Verfahren wird die Datei Web.config der Anwendung bearbeitet, um die Anwendung für die Formularauthentifizierung zu konfigurieren.

  • So konfigurieren Sie die Webanwendung für die Formularauthentifizierung

    1. Öffnen Sie Web.config im Projektmappen-Explorer.

    2. Suchen Sie das <authentication>-Elemen, und ändern Sie das mode-Attribut in Formulare.

    3. Fügen Sie das folgende <Formulare>-Element als untergeordnetes Element des <authentication> -Elements hinzu und legen Sie die Attribute loginUrl, name, timeout und path wie nachstehend gezeigt fest.

        <authentication mode="Formulare">
          <forms loginUrl="logon.aspx" name="sqlAuthCookie" timeout="60" path="/">
          </forms>
        </authentication>
      
    4. Fügen Sie das folgende <authorization>-Element unterhalb des <authentication>-Elements hinzu. Dies sorgt dafür, dass nur authentifizierte Benutzer auf die Anwendung zugreifen können. Das im Vorfeld eingerichtete loginUrl-Attribut des <authentication>-Elements leitet nicht authentifizierte Anforderungen auf die Seite Logon.aspx um.

        <authorization> 
          <deny users="?" />
          <allow users="*" />
        </authorization>
      

 

Entwickeln von Funktionen zum Erzeugen eines Hashes und eines Salt-Wertes

In diesem Verfahren werden der Webanwendung zwei Hilfsmethoden hinzugefügt, und zwar eine zum Erzeugen eines zufälligen Salt-Wertes und eine weitere zum Erzeugen eines Hashes basierend auf dem übergebenen Kennwort und dem Salt-Wert.

  • So entwickeln Sie Funktionen zum Erzeugen eines Hashes und eines Salt-Wertes

    1. Öffnen Sie Logon.aspx.cs und fügen Sie am Anfang der Datei unterhalb der vorhandenen using-Anweisungen die folgenden using-Anweisungen hinzu.

        using System.Security.Cryptography;
        using System.Web.Security;
      
    2. Fügen Sie der WebForm1-Klasse die folgende statische Methode hinzu, um einen zufälligen Salt-Wert zu erzeugen und diesen als eine Base64-verschlüsselte Zeichenfolge zurückzugeben.

        private static string CreateSalt(int size)
        {
          // Kryptografische Zufallszahl mithilfe des Kryptografie-
          // dienstanbieters generieren
          RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
          byte[] buff = new byte[size];
          rng.GetBytes(buff);
          // Base64-Zeichenfolgendarstellung der Zufallszahl zurückgeben
          return Convert.ToBase64String(buff);
        }
      
    3. Fügen Sie die folgende statische Methode hinzu, um einen Hashwert basierend auf dem übergebenen Kennwort und dem Salt-Wert zu erzeugen.

        private static string CreatePasswordHash(string pwd, string salt)
        {
          string saltAndPwd = String.Concat(pwd, salt);
          string hashedPwd = 
                FormsAuthentication.HashPasswordForStoringInConfigFile(
                                                    saltAndPwd, "SHA1");
          return hashedPwd;
        }
      

 

Erstellen einer Benutzerkontendatenbank

In diesem Verfahren wird eine neue Benutzerkontendatenbank in SQL Server erstellt, die eine einzige Benutzertabelle und eine gespeicherte Prozedur zum Abfragen der Benutzerdatenbank enthält.

  • So erstellen Sie eine Benutzerkontendatenbank

    1. Klicken Sie in der Programmgruppe Microsoft SQL Server auf Query Analyzer und stellen Sie die Verbindung zum lokalen Computer mit SQL Server her.

    2. Geben Sie das folgende SQL-Skript ein. Beachten Sie, dass Sie "LocalMachine" am Ende des Skripts durch den Namen Ihres Computers ersetzen müssen.

        USE master
        GO
        -- Datenbank für Sicherheitsinformationen erstellen
        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
        -- gespeicherte Prozedur zur Registrierung von Benutzerdetails erstellen
        CREATE PROCEDURE RegisterUser
        @userName varchar(255),
        @passwordHash varchar(40),
        @salt varchar(10)
        AS
        INSERT INTO Users VALUES(@userName, @passwordHash, @salt)
        GO
        -- gespeicherte Prozedur zur Abfrage von Benutzerdetails erstellen
        CREATE PROCEDURE LookupUser
        @userName varchar(255)
        AS
        SELECT PasswordHash, salt 
        FROM Users
        WHERE UserName = @userName
        GO
        -- Anmeldung für das lokale ASPNET-Konto hinzufügen
        -- Ersetzen Sie in den nachfolgenden Anweisungen "LocalMachine" durch 
        -- den Namen Ihres lokalen Computers
        exec sp_grantlogin [LocalMachine\ASPNET]
        -- Datenbankanmeldung für die UserAccounts-Datenbank für das
        ASPNET-Konto hinzufügen
        exec sp_grantdbaccess [LocalMachine\ASPNET]
        -- Ausführungsberechtigungen für die gespeicherten Prozeduren "LookupUser" und "RegisterUser" gewähren
        procs
        grant execute on LookupUser to [LocalMachine\ASPNET]
        grant execute on RegisterUser to [LocalMachine\ASPNET]
      
    3. Führen Sie die Abfrage aus, um die Datenbank UserAccounts zu erstellen.

    4. Beenden Sie Query Manager.

 

Verwenden von ADO.NET zum Speichern von Kontodetails in der Datenbank

In diesem Verfahren wird der Code der Webanwendung so geändert, dass der übergebene Benutzername, der erzeugte Kennworthash und der Salt-Wert in der Datenbank gespeichert werden.

  • So verwenden Sie ADO.NET zum Speichern von Kontodetails in der Datenbank

    1. Kehren Sie zu Visual Studio .NET zurück und doppelklicken Sie im Webformular auf die Schaltfläche Registrieren, um einen Ereignishandler für das Klickereignis der Schaltfläche zu erstellen.

    2. Fügen Sie der Methode den folgenden Code hinzu.

        string salt = CreateSalt(5);
        string passwordHash = CreatePasswordHash(txtPassword.Text,salt);
        try
        {
          StoreAccountDetails( txtUserName.Text, passwordHash, salt);
        }
        catch(Exception ex)
        {
          lblMessage.Text = ex.Message;
        }
      
    3. Fügen Sie am Anfang der Datei unterhalb der vorhandenen using-Anweisungen die folgende using-Anweisung hinzu.

        using System.Data.SqlClient;
      
    4. Fügen Sie die Hilfsmethode StoreAccountDetails unter Verwendung des nachstehenden Codes hinzu. Dieser Code nutzt ADO.NET für die Herstellung der Verbindung zur UserAccounts-Datenbank und speichert den übergebenen Benutzernamen, den Kennworthash und den Salt-Wert in der Users-Tabelle.

        private void StoreAccountDetails( string userName, 
                                          string passwordHash, 
                                          string salt )
        {
          // Unter "Vorgehensweise: Verwenden von DPAPI (Computerspeicher) von ASP.NET aus" 
          // finden Sie Informationen zum sicheren Speichern von Verbindungszeichenfolgen.
          SqlConnection conn = new SqlConnection( "Server=(local);" +
                                                  "Integrierte Sicherheit=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, der auf Verletzung des Primärschlüssels (doppelter Kontoname)
            // oder andere Datenbankfehler hin geprüft werden muss, wurde aus Gründen der Überschaubarkeit ausgelassen
            neue Ausnahme auslösen ("Ausnahme beim Hinzufügen des Kontos ". + ex.Message);
          }
          finally
          {
            conn.Close();
          } 
        }
      

 

Authentifizieren von Benutzeranmeldeinformationen anhand der Datenbank

In diesem Verfahren wird ADO.NET-Code entwickelt, um den übergebenen Benutzernamen in der Datenbank nachzuschlagen und das übergebene Kennwort anhand eines Vergleichs der Kennworthashes zu überprüfen.

Hinweis: In vielen Formularauthentifizierungsszenarien, in denen eine auf .NET-Rollen basierende Autorisierung verwendet wird, können Sie an diesem Punkt auch die Rollen, denen der Benutzer angehört, aus der Datenbank abrufen. Diese können Sie anschließend zur Erzeugung eines GenericPrincipal-Objekts verwenden, das zum Zwecke der .NET-Autorisierung mit authentifizierten Webanforderungen verbunden werden kann.

Weitere Informationen zur Erstellung eines Tickets für die Formularauthentifizierung, das Benutzerrollen enthält, finden Sie unter "Vorgehensweise: Erstellen von GenericPrincipal-Objekten bei der Formularauthentifizierung" im Abschnitt "Referenz" dieses Handbuches.

  • So authentifizieren Sie Benutzeranmeldeinformationen anhand der Datenbank

    1. Kehren Sie zu Logon.aspx.cs zurück und fügen Sie die private Hilfsmethode VerifyPassword wie im nachstehenden Code gezeigt hinzu.

        private bool VerifyPassword(string suppliedUserName, 
                                    string suppliedPassword )
        { 
          bool passwordMatch = false;
          // Salt und Pwd (Kennwort) basierend auf dem Benutzernamen aus der Datenbank abrufen.
          // Unter "Vorgehensweise: Verwenden von DPAPI (Computerspeicher) von ASP.NET aus", "Vorgehensweise Verwenden von
          DPAPI 
          // (Benutzerspeicher) von ASP.NET aus mit Enterprise Services" und "Vorgehensweise: Erstellen einer DPAPI- 
          // Bibliothek" erfahren Sie, wie DPAPI zur sicheren
          Speicherung von 
          // Verbindungszeichenfolgen verwendet werden kann.
          SqlConnection conn = new SqlConnection( "Server=(local);" + 
                                                  "Integrierte Sicherheit=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(); // Weiter zur einzigen Reihe
            // Ausgabeparameter aus zurückgegebenen Datenstrom zurückgeben
            string dbPasswordHash = reader.GetString(0);
            string salt = reader.GetString(1);
            reader.Close();
            // Nun die vom Benutzer eingegebenen Salt- und Kennwort-Angaben
            // miteinander verketten.
            string passwordAndSalt = String.Concat(suppliedPassword, salt);
            // Nun Hashvorgang durchführen
            string hashedPasswordAndSalt =       
                      FormsAuthentication.HashPasswordForStoringInConfigFile(
                                                      passwordAndSalt, "SHA1");
            // Nun Überprüfung durchführen.
            passwordMatch = hashedPasswordAndSalt.Equals(dbPasswordHash);
          }
          catch (Exception ex)
          {
            throw new Exception("Ausnahme bei Überprüfung des Kennwortes. " + ex.Message);
          }
          finally
          {
            conn.Close();
          }
          return passwordMatch;
        }
      

 

Testen der Anwendung

Im nun folgenden Verfahren testen Sie die Anwendung und registrieren einen Benutzer. Dies führt dazu, dass der Benutzername, der Kennworthash und der Salt-Wert der Users-Tabelle in der UserAccounts-Datenbank hinzugefügt werden. Anschließend melden Sie sich mit diesen Anmeldeinformationen an, um die ordnungsgemäße Funktion der Kennwortüberprüfungsroutinen sicherzustellen.

  • So testen Sie die Anwendung

    1. Kehren Sie zum Anmeldeformular zurück und doppelklicken Sie auf die Schaltfläche Anmelden, um einen Ereignishandler für das Klickereignis der Schaltfläche zu erstellen.

    2. Fügen Sie dem Ereignishandler für das Klickereignis der Schaltfläche Anmelden den folgenden Code hinzu, um die Methode VerifyPassword aufzurufen und eine Meldung anzuzeigen, die angibt, ob der übergebene Benutzername und das Kennwort gültig sind.

        bool passwordVerified = false;
        try
        {
          passwordVerified = VerifyPassword(txtUserName.Text,txtPassword.Text);
        }
        catch(Exception ex)
        {
          lblMessage.Text = ex.Message;
          return;
        }
        if (passwordVerified == true )
        {
          // Der Benutzer ist authentifiziert
          // Zu diesem Zeitpunk wird normalerweise ein Authentifizierungsticket erstellt
          // Dieses kann nachfolgend zum Generieren eines GenericPrincipal-
          // Objektes für die .NET-Autorisierung verwendet werden
          // Details finden Sie unter "Vorgehensweise: Verwenden der Formularauthentifizierung mit 
          GenericPrincipal-
          // Objekten
          lblMessage.Text = "Anmeldung erfolgreich: Benutzer ist authentifiziert";
        }
        else
        {
          lblMessage.Text = "Ungültiger Benutzername oder Kennwort";
        }
      
    3. Klicken Sie im Menü Erstellen auf Projektmappe erstellen.

    4. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf logon.aspx und dann auf In Browser anzeigen.

    5. Geben Sie einen Benutzernamen und ein Kennwort ein und klicken Sie dann auf Registrieren.

    6. Zeigen Sie mithilfe von SQL Server Enterprise Manager den Inhalt der Users-Tabelle an. Es sollte nun eine neue Zeile für den neuen Benutzernamen zusammen mit einem Kennworthash angelegt worden sein.

    7. Kehren Sie zur Anmeldeseite zurück, geben Sie das Kennwort erneut ein und klicken Sie auf Anmelden. Nun sollte die folgende Meldung angezeigt werden: "Anmeldung erfolgreich: Benutzer ist authentifiziert."

    8. Geben Sie nun ein ungültiges Kennwort ein (behalten Sie jedoch den Benutzernamen bei). Nun sollte die Meldung "Ungültiger Benutzername oder Kennwort" angezeigt werden.

    9. Schließen Sie den Internet Explorer.

 

Weitere Ressourcen

Weitere Informationen finden Sie in den folgenden Abschnitten: