Dag,
Ik heb een website draaien geschreven in ASP.NET. De website maakt via het Entity Framework (met MySQL provider) verbinding met een MySQL database, die overigens al een hele tijd draait. De users tabel in die database is al een tijd gevuld met accounts die mensen al een tijdje zonder problemen gebruiken.
Recent heb ik een nieuwe website geschreven die gebruik maakt van dezelfde database, ook via Entity Framework, alles op dezelfde manier zover ik kan vinden. Op deze nieuwe website krijgen sommige gebruikers (lang niet alle) ineens een error te zien tijdens het inloggen.
De exception die gegooid wordt komt maar op een plek voor in m'n code: tijdens het checken van de login gegevens. Het wachtwoord van de gebruiker (tijdens registratie) wordt aangevuld met een 64-karakter lange random salt en daarna met Sha256 gehashed. De salt + hash wordt daarna in de database opgeslagen als wachtwoord hash:
Tijdens het inloggen wordt de input van de gebruiker op dezelfde manier gehashed en de twee hashes worden vergeleken. De salt (64 karakters die dus al aan de hash vastgeplakt zit) wordt daar dus eerst vanaf gehaald, waarna de hash van de input gevormd kan worden en vergeleken kan worden met de opgeslagen hash:
Het eerste wat dus gebeurt is een check of de hash wel 128 karakters is (64 van de salt + 64 van de hash zelf). Voorheen werd hier een exception gegooid als dat niet zo was, en dat is precies de exception die getoond werd. Dat heb ik nu dus vervangen met een log van de hash en zijn lengte, om erachter te komen hoe het kan dat de hash niet 128 karakters is.
Het vreemde: als ik in de database kijk naar het account in kwestie dan is de hash gewoon netjes 128 karakters. Sterker nog: als ik zelf probeer in te loggen op zijn account, krijg ik de fout niet. Ik weet uiteraard zijn wachtwoord niet dus krijg gewoon te zien dat het wachtwoord verkeerd is, maar ik krijg niet de exception, de hash is dan netjes 128 karakters.
Met deze log heb ik nu kunnen zien dat 'correctHash' een lege string is. Op de een of andere manier worden zijn account details dus niet juist uit de database geladen en word zijn correctHash niet gezet, waar het dus fout gaat. Let op: in mijn geval ging het goed, met hetzelfde account op dezelfde live website!!
Om dit verder uit te zoeken heb ik nog een log toegevoegd, vlak voordat deze ValidatePassword functie aangeroepen wordt:
De eerste regel haalt via Entity Framework de user op met het ingevoerde 'custid' (customer id == username). De properties van het User object worden daarna gelogd (Id, CustId, Name en PasswordHash). Meteen daarna wordt de ValidatePassword functie aangeroepen, met dezelfde PasswordHash property op hetzelfde User object.
Je raadt het misschien al, maar de logging laat de volgende info zien:
Bij de eerste logging komen de user details gewoon door, inclusief de PasswordHash van 128 karakters (in dit geval heb ik de hash vervangen door 'xxxxx...', het is een hash dus het zou in principe veilig moeten zijn, maar toch, uiteraard staat de juiste hash in de logging).
Nog geen seconde later is 'correctHash' ineens leeg. Dit is dezelfde PasswordHash property op hetzelfde User object. Het ene moment is de hash er, het andere moment niet meer.
Ik snap er niets meer van
Weet iemand waarom dit mis gaat? Ik verwacht dat het iets met Entity Framework te maken heeft, waarbij de properties niet op tijd geladen worden of iets dergelijks? Iets met lazy loading misschien? Ik kan het me niet voorstellen, want de hash word gewoon getoond in de logging, en de volgende regel is hij ineens leeg...
Help?
EDIT
Inmiddels kan de gebruiker weer inloggen. Maar ik snap nog steeds niet wat er nu mis ging, laat staan waarom het nu ineens wel werkt. Ik verwacht dit probleem nog wel vaker tegen te komen (twee gebruikers hebben er nu last van gehad) dus ik zou graag weten wat er mis gaat...
Ik heb een website draaien geschreven in ASP.NET. De website maakt via het Entity Framework (met MySQL provider) verbinding met een MySQL database, die overigens al een hele tijd draait. De users tabel in die database is al een tijd gevuld met accounts die mensen al een tijdje zonder problemen gebruiken.
Recent heb ik een nieuwe website geschreven die gebruik maakt van dezelfde database, ook via Entity Framework, alles op dezelfde manier zover ik kan vinden. Op deze nieuwe website krijgen sommige gebruikers (lang niet alle) ineens een error te zien tijdens het inloggen.
De exception die gegooid wordt komt maar op een plek voor in m'n code: tijdens het checken van de login gegevens. Het wachtwoord van de gebruiker (tijdens registratie) wordt aangevuld met een 64-karakter lange random salt en daarna met Sha256 gehashed. De salt + hash wordt daarna in de database opgeslagen als wachtwoord hash:
C#:
1
2
3
4
5
6
| public static string HashPassword(string password) { string salt = GetRandomSalt(); string hash = Sha256Hex(salt + password); return salt + hash; } |
Tijdens het inloggen wordt de input van de gebruiker op dezelfde manier gehashed en de twee hashes worden vergeleken. De salt (64 karakters die dus al aan de hash vastgeplakt zit) wordt daar dus eerst vanaf gehaald, waarna de hash van de input gevormd kan worden en vergeleken kan worden met de opgeslagen hash:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
| public static bool ValidatePassword(string password, string correctHash) { if (correctHash.Length < 128) { Log.Instance.LogError(new Exception("correctHash is not 128 chars. correctHash is '" + correctHash + "' and " + correctHash.Length + " chars.")); return false; } string salt = correctHash.Substring(0, 64); string validHash = correctHash.Substring(64, 64); string passHash = Sha256Hex(salt + password); return string.Compare(validHash, passHash) == 0; } |
Het eerste wat dus gebeurt is een check of de hash wel 128 karakters is (64 van de salt + 64 van de hash zelf). Voorheen werd hier een exception gegooid als dat niet zo was, en dat is precies de exception die getoond werd. Dat heb ik nu dus vervangen met een log van de hash en zijn lengte, om erachter te komen hoe het kan dat de hash niet 128 karakters is.
Het vreemde: als ik in de database kijk naar het account in kwestie dan is de hash gewoon netjes 128 karakters. Sterker nog: als ik zelf probeer in te loggen op zijn account, krijg ik de fout niet. Ik weet uiteraard zijn wachtwoord niet dus krijg gewoon te zien dat het wachtwoord verkeerd is, maar ik krijg niet de exception, de hash is dan netjes 128 karakters.
Met deze log heb ik nu kunnen zien dat 'correctHash' een lege string is. Op de een of andere manier worden zijn account details dus niet juist uit de database geladen en word zijn correctHash niet gezet, waar het dus fout gaat. Let op: in mijn geval ging het goed, met hetzelfde account op dezelfde live website!!
Om dit verder uit te zoeken heb ik nog een log toegevoegd, vlak voordat deze ValidatePassword functie aangeroepen wordt:
C#:
1
2
3
4
5
6
7
8
9
10
11
| User user = entities.users.FirstOrDefault(u => u.Custid == custid); // (user == null) check weg gelaten... Log.Instance.LogInfo(string.Format("User logging in: Id:{0}, Custid:{1}, Name:{2}, PwHash:{3}.", user.Id, user.Custid, user.Username, user.PasswordHash)); if (!PasswordHash.ValidatePassword(password, user.PasswordHash)) { // Invalid password... } |
De eerste regel haalt via Entity Framework de user op met het ingevoerde 'custid' (customer id == username). De properties van het User object worden daarna gelogd (Id, CustId, Name en PasswordHash). Meteen daarna wordt de ValidatePassword functie aangeroepen, met dezelfde PasswordHash property op hetzelfde User object.
Je raadt het misschien al, maar de logging laat de volgende info zien:
code:
1
2
3
4
5
6
| ---------- 12-10-2012 20:16:49| Info: User logging in: Id:112, Custid:94587, Name:<weg>, PwHash:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx. ---------- 12-10-2012 20:16:49| Error: correctHash is not 128 chars. correctHash is '' and 0 chars. System.Exception: correctHash is not 128 chars. correctHash is '' and 0 chars. |
Bij de eerste logging komen de user details gewoon door, inclusief de PasswordHash van 128 karakters (in dit geval heb ik de hash vervangen door 'xxxxx...', het is een hash dus het zou in principe veilig moeten zijn, maar toch, uiteraard staat de juiste hash in de logging).
Nog geen seconde later is 'correctHash' ineens leeg. Dit is dezelfde PasswordHash property op hetzelfde User object. Het ene moment is de hash er, het andere moment niet meer.
Ik snap er niets meer van

Weet iemand waarom dit mis gaat? Ik verwacht dat het iets met Entity Framework te maken heeft, waarbij de properties niet op tijd geladen worden of iets dergelijks? Iets met lazy loading misschien? Ik kan het me niet voorstellen, want de hash word gewoon getoond in de logging, en de volgende regel is hij ineens leeg...
Help?

EDIT
Inmiddels kan de gebruiker weer inloggen. Maar ik snap nog steeds niet wat er nu mis ging, laat staan waarom het nu ineens wel werkt. Ik verwacht dit probleem nog wel vaker tegen te komen (twee gebruikers hebben er nu last van gehad) dus ik zou graag weten wat er mis gaat...