Files
LehrerApp/LehrerApp.Api/PasswordHasher.cs
adminandClaude Sonnet 5 6f9de325d5 Baustein 1: Server-Auth-Fix (Kapitel 10)
/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>
2026-08-17 11:20:19 +02:00

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);
}
}