security: Audit-Log für alle Klartext-Passwort-Reads (CRITICAL)
Pentest-Finding "Klartext-Passwörter über API abrufbar (HIGH, post-auth)" adressiert: reversible Verschlüsselung der Anbieter-/Portal-Logins ist by-design (Feature "Login anzeigen" braucht sie zwingend), aber jeder einzelne Decrypt-Vorgang muss im Audit-Log nachvollziehbar sein. Bisher schrieb KEINER der 6 betroffenen Endpoints einen Eintrag. Behoben in: - getPortalPassword (Customer-Portal-Login) - getContractPassword (Anbieter-Login z.B. Vattenfall, EWE, …) - getSimCardCredentials (PIN/PUK) - getInternetCredentials (DSL-Login) - getSipCredentials (Telefon-/VoIP-Login) - getMailboxCredentials (Stressfrei-IMAP/SMTP) Alle nutzen `action: 'READ'` mit eigenem ResourceType + Sensitivity CRITICAL via determineSensitivity-Map. Label nennt explizit "Klartext … entschlüsselt" + Resource-ID, damit im AuditLog-Viewer auf einen Blick erkennbar ist, wer wann welches Passwort eingesehen hat (DSGVO + Insider-Threat-Erkennung). Live verifiziert: nach Klick auf getPortalPassword erscheint im AuditLog der Eintrag "READ PortalPassword CRITICAL – Klartext-Portal- Passwort von Kunde #1 entschlüsselt". Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -321,6 +321,14 @@ export async function getContractPassword(req: AuthRequest, res: Response): Prom
|
||||
} as ApiResponse);
|
||||
return;
|
||||
}
|
||||
// Klartext-Passwort-Read auditieren (CRITICAL)
|
||||
await logChange({
|
||||
req,
|
||||
action: 'READ',
|
||||
resourceType: 'ContractPassword',
|
||||
resourceId: contractId.toString(),
|
||||
label: `Klartext-Anbieter-Passwort von Vertrag #${contractId} entschlüsselt`,
|
||||
});
|
||||
res.json({ success: true, data: { password } } as ApiResponse);
|
||||
} catch (error) {
|
||||
res.status(500).json({
|
||||
@@ -345,6 +353,14 @@ export async function getSimCardCredentials(req: AuthRequest, res: Response): Pr
|
||||
if (!(await canAccessContract(req, res, sim.mobileDetails.contractId))) return;
|
||||
|
||||
const credentials = await contractService.getSimCardCredentials(simCardId);
|
||||
// Klartext-Read (PIN/PUK) auditieren (CRITICAL)
|
||||
await logChange({
|
||||
req,
|
||||
action: 'READ',
|
||||
resourceType: 'SimCardCredentials',
|
||||
resourceId: simCardId.toString(),
|
||||
label: `Klartext-SIM-Karten-PIN/PUK von SIM #${simCardId} (Vertrag #${sim.mobileDetails.contractId}) entschlüsselt`,
|
||||
});
|
||||
res.json({ success: true, data: credentials } as ApiResponse);
|
||||
} catch (error) {
|
||||
res.status(500).json({
|
||||
@@ -360,6 +376,14 @@ export async function getInternetCredentials(req: AuthRequest, res: Response): P
|
||||
if (!(await canAccessContract(req, res, contractId))) return;
|
||||
|
||||
const credentials = await contractService.getInternetCredentials(contractId);
|
||||
// Klartext-DSL/Internet-Login auditieren (CRITICAL)
|
||||
await logChange({
|
||||
req,
|
||||
action: 'READ',
|
||||
resourceType: 'InternetCredentials',
|
||||
resourceId: contractId.toString(),
|
||||
label: `Klartext-Internet-Zugangsdaten von Vertrag #${contractId} entschlüsselt`,
|
||||
});
|
||||
res.json({ success: true, data: credentials } as ApiResponse);
|
||||
} catch (error) {
|
||||
res.status(500).json({
|
||||
@@ -384,6 +408,14 @@ export async function getSipCredentials(req: AuthRequest, res: Response): Promis
|
||||
if (!(await canAccessContract(req, res, phone.internetDetails.contractId))) return;
|
||||
|
||||
const credentials = await contractService.getSipCredentials(phoneNumberId);
|
||||
// Klartext-SIP/Telefon-Login auditieren (CRITICAL)
|
||||
await logChange({
|
||||
req,
|
||||
action: 'READ',
|
||||
resourceType: 'SipCredentials',
|
||||
resourceId: phoneNumberId.toString(),
|
||||
label: `Klartext-SIP-Zugangsdaten von Rufnummer #${phoneNumberId} (Vertrag #${phone.internetDetails.contractId}) entschlüsselt`,
|
||||
});
|
||||
res.json({ success: true, data: credentials } as ApiResponse);
|
||||
} catch (error) {
|
||||
res.status(500).json({
|
||||
|
||||
Reference in New Issue
Block a user