Teknikdags: Lagra användarnamn och "hashade" lösenord.


Vi har alldeles nyss inlett utvecklingen av den demo-applikation (som tidigare kallades referens-applikation, vilket är fel) som vi avser att använda under seminarier, webbsändningar och tekniska artiklar i framtiden. Jag har redan funderat en del på arkitekturen tillsammans med några av mina kollegor och vi siktar på att använda vår referensarkitetktur “enligt boken” för att skapa en flexibel arkitektur som ger oss så stora möjligheter som möjligt att gå vidare i olika scenarios.

Det som jag också försökt att inleda är implementationen av en skräddarsydd MembershipProvider för ASP.NET 2.0, skälet till att jag valt en egen och inte ASP.NET’s inbyggda är att den inbyggda genererar väldigt många tabeller som vi initiellt inte behöver (rollhantering, personifiering) utan vi vill försöka att hålla den första implementationen så pass enkel så att det är lätt att sätta sig in i den för att sedan kunna fokusera på detaljer för vidareutveckling.

Den MembershipProvider som jag skapat ligger nu i presentations-skiktet och gör uppslag och uppdateringar genom arkitekturen, eventuellt så kan vi tillåta läsningar direkt från presentations-skiktet till dataskiktet. Jag har också valt att skapa en komponent (klass) i mellanskiktet där logiken ligger för att validera och skapa användarna, denna komponent gör sedan uppslag och uppdateringar mot databasen. Det finns massvis med frågor och alternativ och det är där som jag hoppas att diskussionen kan inledas när vi släpper den första versionen senare.

Sättet som jag lagrar användaruppgifterna på i databasen är genom att enbart lagra “hashade” lösenord, och då även saltade sådana. Den metod som jag använder ser ut enligt följande:

private static string HashPassword(string password, ref string passwordSalt)

{
    Rfc2898DeriveBytes db = new Rfc2898DeriveBytes(password, 32, 1000);
    
    if (passwordSalt == null)
        passwordSalt = Convert.ToBase64String(db.Salt);
    else
        db.Salt = Convert.FromBase64String(passwordSalt);
 
    byte[] passwordHash = db.GetBytes(32);
    return Convert.ToBase64String(passwordHash);
}

Den här metoden använder .NET Framework 2.0’s inbyggda klasser och ramverk för att returnera ett saltat och “hashat” lösenord som antingen kan lagras i databasen alternativt jämföras med det som redan finns lagrat sedan tidigare.

Hur gör du för att lagra dina lösenord, vilken metod passar dig?


Comments (7)

  1. Kristofer Liljeblad says:

    Jag använder ungefär den metod som du tänkt använda, men jag använder mig av Microsoft.Practices.EnterpriseLibrary.Security.Cryptography vilket gör det hela ännu lite mer flexibelt för slutanvändaren som kan välja provider och annat själv.

    Ett utdrag ur ChangePassword(…)

    string passwordHash = Cryptographer.CreateHash(HASH_PROVIDER, newPassword);

    Ett exempel ur min funktion ValidateUser(…)

    return Cryptographer.CompareHash(HASH_PROVIDER, password, passwordHash);

  2. JohanLindfors says:

    Enterprise Library är ett absolut "nästa steg" i den här applikationen. Bra förslag!

  3. Jonas Lewin says:

    Ja tack. Mer av enterprise library. Dels för att jag kan det för dåligt, dels för att det är "by the book" hos er 🙂

  4. Som min kollega Johan Lindfors bloggat om så skissar vi i teamet på ett exempelprojekt som ska användas

  5. Henrik Hagberg says:

    Mycket intressant ämne!

    Jag tänkte ställa ett par följdfråga ang. er lösning.

    Att salta lösenordet (om saltet är bra som i detta fall) är ju ett bra sätt att eliminera dictionary attacker mot vanliga hashningar/krypteringar.

    Men ponera att angriparen skulle få tag i hash OCH salt (vilket väl är relativt troligt om han nu kan få tag i hashen) hur stor är chansen att han lyckas brute-forcea lösenordet inom rimlig tid? Rekommenderar ni någon lösning för att minimera möjligheten att komma över både Hash och Salt?

  6. JohanLindfors says:

    Hej Henrik, jag har ingen formell rekommendation men ser flera potentiella lösningar. En som jag själv känner mig bekväm inför är att kräva att lösenord måste bytas kontinuerligt, om det då också görs en uppskattning på hur lång tid vi realistiskt kan tänka oss att det tar för någon att "brute-forcea" lösenordet så kan vi hitta perioden. En kortare period kan eventuellt också användas för att se till att kontot överhuvudtaget är aktivt och används för att slippa konton som ligger och skräpar.

    En alternativ möjlighet som kan vara ännu bättre är att inte använda lösenord överhuvudtaget. Vi kan till exempel använda Windows CardSpace för att slippa just lagringen av lösenord och det underlättar också för användarna som slipper komma ihåg sina uppgifter.

    Hör gärna av dig igen!

  7. Henrik Hagberg says:

    Tackar för inputen Johan!

    I detta läge lutar det nog mot hash+salt och att säkra upp detta så bra som möjligt, det borde räcka.

    Ser däremot fram emot att få tid och möjlighet att sätta mig in i CardSpace, det verkar vara en mycket intressant teknik.