Mitarbeiter-Passwörter auf 25 Zeichen (BSI-Empfehlung)

Portal-Customer-Schwellwert bleibt 12 (Handy-Eingabe → längere PWs
erhöhen Reuse-Risiko). Mitarbeiter/Admin nutzen Passwort-Manager,
für die kostet die Länge nichts.

passwordGenerator.ts:
- STAFF_MIN_PASSWORD_LENGTH = 25, PORTAL_MIN_PASSWORD_LENGTH = 12
- validatePasswordComplexity({ minLength }) parametrisiert

Mitarbeiter-Pfade auf 25:
- createUser, register, setUserPassword
- confirmPasswordReset: Audience aus Token bestimmen
  (getPasswordResetAudience), User → 25, Customer → 12. Kein
  Body-Hint, damit kein Downgrade-Trick möglich.

Portal-Pfade unverändert (default 12):
- setPortalPassword, changeInitialPortalPassword

Seed-Admin:
- 28-char Zufallspasswort (statt 16) mit allen 4 Klassen garantiert
- SEED_ADMIN_PASSWORD-ENV nur akzeptiert wenn ≥ 25 Zeichen,
  sonst Log-Warnung + Random-Fallback

Frontend:
- UserList: Hinweis "Mind. 25 Zeichen". Update + PW gleichzeitig →
  zwei API-Calls (PUT + POST /users/:id/password) statt
  Password im Body durchzuschmuggeln (Backend strippt es eh)
- PasswordResetConfirm: Hinweis "Mind. 12 (Mitarbeiter: 25)"
- userApi.setPassword(id, password) neu

Live-verifiziert:
- POST /users/6/password "Hallo123!Test" (12) → 400 "mindestens 25"
- POST /users/6/password "MeinExtremLangesPW2026!Test" → 200,
  Login mit neuem PW → success
- POST /customers/3/portal/password "Hallo123!Test" (12) → 200
- POST /users createUser mit 12-char-PW → 400 "mindestens 25"

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-18 15:19:58 +02:00
parent cf8c6c84c2
commit 3e1fc3eab2
9 changed files with 127 additions and 25 deletions
+8 -3
View File
@@ -238,7 +238,9 @@ async function main() {
const pick = (s: string) => s[Math.floor(Math.random() * s.length)];
// mind. einen aus jeder Klasse + Rest zufällig
const chars = [pick(upper), pick(lower), pick(digits), pick(special)];
for (let i = chars.length; i < 16; i++) chars.push(pick(all));
// 28 Zeichen → Komplexität + komfortable Marge über dem 25-Zeichen-
// Mitarbeiter-Schwellwert (Pentest Runde 13).
for (let i = chars.length; i < 28; i++) chars.push(pick(all));
// Fisher-Yates Shuffle (sonst stehen die garantierten Klassen-Zeichen am Anfang)
for (let i = chars.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
@@ -248,7 +250,7 @@ async function main() {
}
const envPassword = process.env.SEED_ADMIN_PASSWORD;
const adminPlainPassword = envPassword && envPassword.length >= 12
const adminPlainPassword = envPassword && envPassword.length >= 25
? envPassword
: generateInitialPassword();
const hashedPassword = await bcrypt.hash(adminPlainPassword, 12);
@@ -269,9 +271,12 @@ async function main() {
console.log('========================================================');
console.log(' Admin-User: admin@admin.com');
if (envPassword) {
if (envPassword && envPassword.length >= 25) {
console.log(' Passwort: aus SEED_ADMIN_PASSWORD');
} else {
if (envPassword && envPassword.length < 25) {
console.log(' ⚠️ SEED_ADMIN_PASSWORD < 25 Zeichen, wird ignoriert!');
}
console.log(` Initial-Passwort: ${adminPlainPassword}`);
console.log(' ⚠️ Dieses Passwort wird hier EINMAL ausgegeben!');
console.log(' Bitte sofort nach dem ersten Login ändern.');