Portal-Passwort: encrypted ohne Hash gilt jetzt als desync (R143)

Pentester R143 (Robustheit): getCustomerPortalPassword lieferte 'ok',
wenn portalPasswordEncrypted gesetzt, aber portalPasswordHash null ist.
Ohne Hash ist ein Login unmoeglich -> ein revealtes Passwort waere
irrefuehrend. Jetzt -> desync (Reveal/Send blocken mit 409). Aktuell
ueber die API nicht erreichbar, nur als DB-Altlast; jetzt sauber
abgefangen.

Verifiziert: encrypted+hash=null -> desync.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-12 10:06:00 +02:00
co-authored by Claude Opus 4.8
parent 5047bfaab3
commit bbe1aed230
+12 -6
View File
@@ -441,14 +441,20 @@ export async function getCustomerPortalPassword(customerId: number): Promise<Por
return { status: 'desync' };
}
// Ohne Login-Hash ist ein Login gar nicht möglich ein gespeichertes
// Klartext-Passwort wäre irreführend (Support würde etwas vorlesen, das
// nirgends funktioniert). Als inkonsistent behandeln (Pentest R143).
if (!customer.portalPasswordHash) {
console.warn(`[getCustomerPortalPassword] Desync: verschlüsseltes Passwort ohne Login-Hash (Kunde #${customerId})`);
return { status: 'desync' };
}
// Muss zum Login-Hash passen sonst ist der gespeicherte Klartext veraltet
// und würde beim Login fehlschlagen.
if (customer.portalPasswordHash) {
const matches = await bcrypt.compare(decrypted, customer.portalPasswordHash);
if (!matches) {
console.warn(`[getCustomerPortalPassword] Desync: gespeichertes Passwort passt nicht zum Login-Hash (Kunde #${customerId})`);
return { status: 'desync' };
}
const matches = await bcrypt.compare(decrypted, customer.portalPasswordHash);
if (!matches) {
console.warn(`[getCustomerPortalPassword] Desync: gespeichertes Passwort passt nicht zum Login-Hash (Kunde #${customerId})`);
return { status: 'desync' };
}
return { status: 'ok', password: decrypted };