Authentifizierung mit serverseitigen Sitzungen, CSRF und Rollen
Passwoerter mit Argon2id, im Cookie steht nur ein Token und in der Datenbank dessen Hash. Das CSRF-Token wird per HMAC aus dem Sitzungstoken abgeleitet statt separat gespeichert - ohne das httpOnly-Cookie ist es nicht herstellbar. TOTP ist optional und wird erst nach einem bestaetigten Code scharf geschaltet, damit sich niemand bei der Einrichtung aussperrt.
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
import { hash, verify } from '@node-rs/argon2';
|
||||
|
||||
// OWASP-Empfehlung fuer Argon2id: 19 MiB, 2 Durchlaeufe, Parallelitaet 1.
|
||||
const options = {
|
||||
memoryCost: 19456,
|
||||
timeCost: 2,
|
||||
parallelism: 1,
|
||||
} as const;
|
||||
|
||||
export function hashPassword(plain: string): Promise<string> {
|
||||
return hash(plain, options);
|
||||
}
|
||||
|
||||
export async function verifyPassword(digest: string, plain: string): Promise<boolean> {
|
||||
try {
|
||||
return await verify(digest, plain, options);
|
||||
} catch {
|
||||
// Kaputter oder fremdformatiger Hash gilt als nicht passend.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const MIN_LENGTH = 12;
|
||||
|
||||
export function validatePasswordStrength(plain: string): string | null {
|
||||
if (plain.length < MIN_LENGTH) {
|
||||
return `Passwort muss mindestens ${MIN_LENGTH} Zeichen lang sein`;
|
||||
}
|
||||
if (!/[a-z]/.test(plain) || !/[A-Z]/.test(plain)) {
|
||||
return 'Passwort muss Gross- und Kleinbuchstaben enthalten';
|
||||
}
|
||||
if (!/[0-9]/.test(plain)) {
|
||||
return 'Passwort muss mindestens eine Ziffer enthalten';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
Reference in New Issue
Block a user