Migration zu ASP.NET Core RC2 Wie viel Authentifizierung hättens denn gern?

Das Passwort, bitte

Published on Thursday, May 12, 2016 10:30:41 AM UTC in Programming & Security

Im letzten Post habe ich mich drüber ausgelassen, wo man mit chirurgischer Präzision in ASP.NET Core ansetzen kann, um einen Authentifizierungsmechanismus mit minimalem Aufwand einzuklinken. Bleibt noch zu klären, wie eine solche Implementierung aussehen sollte. Mit nur einer Hand voll Regeln ist man beim Verwalten von Passwörter bzw. Nutzerzugängen auf der sicheren Seite.

  • Keine Experimente. Man sollte grundsätzlich vermeiden, bekannte kryptografische Algorithmen selbst zu implementieren oder gar eigene Ideen und Verbesserungen einfließen zu lassen. Dabei kann man im Tretminenfeld der Implementierungsfehler nur verlieren.
  • Ignorance is bliss. Wer ein Passwort gar nicht kennt, kann es auch nicht an einen Angreifer verlieren. Zum Verwalten von Authentifizierungsdaten immer Hashing-Algorithmen verwenden, niemals reversible Verschlüsselung.
  • Lieber einen Stock mehr in die Speichen. Moderne Hashing-Algorithmen erschweren Angriffe schon dadurch, dass sie bewusst langsam arbeiten (etwa durch die Verwendung von vielen Iterationen). Trotzdem sollte man Angreifern das Leben noch schwerer machen und beispielsweise Rainbow-Table-Attacken verhindern, indem man Salts verwendet.

Hört sich kompliziert an, ist aber in der Umsetzung gar nicht so dramatisch.

Neben diesen Details zur Implementierung gibt es noch weitere Empfehlungen zum Gesamtprozess oder begleitenden Policies, etwa zur Passwortstärke oder -länge oder das Involvieren mehrerer Authentifizierungsfaktoren. Details dazu gibt es z.B. bei OWASP.org.

Implementierung in .NET

Eine der Empfehlungen für Hashing-Algorithmen ist PBKDF2 (rollte von der Zunge wie nichts, oder?). Leider hat sich Microsoft dazu entschlossen, die Implementierung in .NET nach (dem zugehörigen RFC-Dokument der IETF)[https://tools.ietf.org/html/rfc2898] zu benennen: Rfc2898DeriveBytes. Zum Generieren des zugehörigen Salts empfielt sich ein kryptografischer Zufallszahlengenerator, den man schon leichter als RNGCryptoServiceProvider in .NET finden kann. Mit diesen Hilfsmitteln bewaffnet, sieht eine einfache Implementierung z.B. so aus:

private byte[] CreateSalt()
{
    byte[] salt = new byte[SaltSize];
    using (var rngCsp = new RNGCryptoServiceProvider())
    {
        rngCsp.GetBytes(salt);
        return salt;
    }
}

private string HashPassword(string password, byte[] salt)
{
    using (var pbkdf2 = new Rfc2898DeriveBytes(password, salt))
    {
        var hash = pbkdf2.GetBytes(HashSize);
        var rawData = salt.Concat(hash).ToArray();
        var encodedHash = Convert.ToBase64String(rawData);
        return encodedHash;
    }
}

Wobei SaltSize = 8 und HashSize = 32 sinnvolle Ausgangsgrößen sind. Die Konvertierung nach Base64 ist technisch natürlich nicht nötig, erlaubt es aber, den Hash als lesbaren Text abzulegen statt mit unhandlicheren Byte-Arrays zu hantieren. Wer möchte, darf dem Konstruktor des Hashing-Algorithmus auch noch die Zahl der gewünschten Iterationen mitgeben, wobei man hier eher Richtung 10000 aufwärts tendieren sollte (Microsofts Empfehlung laut MSDN sind minimal 1000).

Zum Prüfen eines eingegebenen Passworts muss natürlich das ursprünglich verwendete Salt verwendet werden, um den Vergleichshash zu erzeugen. Das heißt in etwa:

public bool ComparePassword(string storedPassword, string enteredPassword)
{
    var rawData = Convert.FromBase64String(storedPassword);
    var salt = rawData.Take(SaltSize).ToArray();
    var hashedPassword = HashPassword(enteredPassword, salt);
    return storedPassword.Equals(hashedPassword);
}

Die Art der Persistierung des Hashes ist dabei zunächst einmal unerheblich.

Wie man sieht, kann man auch mit wenigen Hilfsmittel und ohne riesigen Aufwand eine sinnvolle und ausreichend abgesicherte Art der Zugangsverwaltung umsetzen. Heutzutage gibt es damit eigentlich keine Entschuldigung mehr für Klartext-Passwörter in leicht zugänglichen Datenbanken oder ähnliche Fehltritte, wie sie sich leider auch Industriegrößen tatsächlich immer noch erlauben.

Tags: Hashing · Passwörter