/api/auth/login und /api/auth/register akzeptierten zuvor jeden beliebigen Nutzernamen/Passwort und stellten ein gueltiges 30-Tage-JWT aus - konkrete, ausnutzbare Luecke bei echtem Deployment. - PasswordHasher (PBKDF2, Salt pro Nutzer) + UserStore (LiteDB) statt des ungeprueften Stubs - /api/auth/register ersatzlos entfernt (kein offener Registrierungs-Endpunkt fuer ein Einzel-/Familien-Deployment) - Neue Nutzer per CLI (dotnet LehrerApp.Api.dll create-user <name>), dokumentiert in docker/README.md - Neues Testprojekt LehrerApp.Api.Tests (bisher als einziges Projekt ohne Tests) Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
28 lines
991 B
C#
28 lines
991 B
C#
using System.Security.Cryptography;
|
|
|
|
namespace LehrerApp.Api;
|
|
|
|
public static class PasswordHasher
|
|
{
|
|
private const int Iterations = 100_000;
|
|
private const int SaltSize = 16;
|
|
private const int HashSize = 32;
|
|
|
|
public static string Hash(string password)
|
|
{
|
|
var salt = RandomNumberGenerator.GetBytes(SaltSize);
|
|
var hash = Rfc2898DeriveBytes.Pbkdf2(password, salt, Iterations, HashAlgorithmName.SHA256, HashSize);
|
|
return $"{Convert.ToBase64String(salt)}:{Convert.ToBase64String(hash)}";
|
|
}
|
|
|
|
public static bool Verify(string password, string stored)
|
|
{
|
|
var parts = stored.Split(':');
|
|
if (parts.Length != 2) return false;
|
|
var salt = Convert.FromBase64String(parts[0]);
|
|
var expected = Convert.FromBase64String(parts[1]);
|
|
var actual = Rfc2898DeriveBytes.Pbkdf2(password, salt, Iterations, HashAlgorithmName.SHA256, HashSize);
|
|
return CryptographicOperations.FixedTimeEquals(actual, expected);
|
|
}
|
|
}
|