Unzureichend geschützte Anmeldedaten
Beschreibung
Unzureichend geschützte Anmeldedaten tritt auf, wenn ein Produkt Authentifizierungs-Anmeldedaten mit einer unsicheren Methode überträgt oder speichert, die anfällig für unbefugtes Abfangen und/oder Abrufen ist. Dies umfasst das Speichern von Passwörtern im Klartext, die Verwendung schwacher Verschlüsselung, die Übertragung von Anmeldedaten über unverschlüsselte Kanäle, das Speichern von Anmeldedaten an leicht zugänglichen Orten, die Verwendung reversibler Kodierung anstelle von ordnungsgemäßem Hashing oder das Versäumnis, Anmeldedatenspeicher ordnungsgemäß zu schützen. Wenn Anmeldedaten nicht angemessen geschützt sind, können Angreifer, die irgendeinen Zugriff erlangen, sie oft abrufen und ihre Privilegien eskalieren oder sich lateral durch das Netzwerk bewegen.
Risiko
Fehler beim Schutz von Anmeldedaten haben katastrophale Konsequenzen. CVE-2025-58130 in Apache Fineract legt Anmeldedaten in Finanzinstitutionen offen, was möglicherweise zu unbefugtem Zugriff auf sensible Finanzdaten, Betrug und DSGVO-Verstößen führt. FortiOS (FG-IR-24-111) ermöglicht privilegierten Angreifern, LDAP-Anmeldedaten abzurufen, indem sie zu bösartigen Servern umleiten. CVE-2025-37728 in Elastic Kibana legt zwischengespeicherte Crowdstrike-Anmeldedaten über Kibana-Spaces hinweg offen und untergräbt Sicherheitstelemetrie und Incident-Response-Fähigkeiten. Diese Schwachstellen ermöglichen Angreifern, sich als legitime Benutzer auszugeben, auf sensible Systeme zuzugreifen und durch gestohlene Anmeldedaten dauerhaften Zugriff aufrechtzuerhalten.
Lösung
Speichern Sie Anmeldedaten niemals im Klartext. Verwenden Sie starke, adaptive Hashing-Algorithmen (Argon2, bcrypt, scrypt) für Passwörter. Verschlüsseln Sie Anmeldedatenspeicher mit stärker Verschlüsselung (AES-256) und schützen Sie Verschlüsselungsschlüssel separat. Verwenden Sie sichere Credential-Vaults (HashiCorp Vault, AWS Secrets Manager). Übertragen Sie Anmeldedaten nur über verschlüsselte Kanäle (TLS). Implementieren Sie ordnungsgemäße Zugriffskontrollen für Anmeldedatenspeicher. Rotieren Sie Anmeldedaten regelmäßig. Verwenden Sie Hardware-Sicherheitsmodule (HSMs) für kritisches Schlüsselmaterial. Implementieren Sie Multi-Faktor-Authentifizierung, um die Auswirkungen von Anmeldedatendiebstahl zu reduzieren.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Authentifizierung | Bereich: Anmeldedatendiebstahl Angreifer rufen Anmeldedaten ab und geben sich als legitime Benutzer aus. |
| Zugriffskontrolle | Bereich: Unbefugter Zugriff Gestohlene Anmeldedaten bieten Zugriff auf Systeme, Daten und Netzwerkressourcen. |
| Vertraulichkeit | Bereich: Laterale Bewegung Anmeldedaten funktionieren oft über mehrere Systeme hinweg und ermöglichen Angreifern, sich durch das Netzwerk auszubreiten. |
Beispielcode
Verwundbarer Code
# VERWUNDBAR: Passwort im Klartext speichern
import sqlite3
def create_user(username, password):
conn = sqlite3.connect('users.db')
cursor = conn.cursor()
# Passwort als Klartext gespeichert - jeder mit DB-Zugriff kann es lesen!
cursor.execute("INSERT INTO users (username, password) VALUES (?, ?)",
(username, password))
conn.commit()
# VERWUNDBAR: Reversible Kodierung statt Hashing
import base64
def store_password(password):
# Base64 ist Kodierung, KEINE Verschlüsselung - trivial reversibel!
encoded = base64.b64encode(password.encode())
return encoded
# VERWUNDBAR: Anmeldedaten in Konfigurationsdatei
config = {
'ldap_server': 'ldap://corp.example.com',
'ldap_user': 'cn=admin,dc=example,dc=com',
'ldap_password': 'AdminPassword123!' # Klartext-Anmeldedaten!
}
// VERWUNDBAR: Schwacher Hashing-Algorithmus
import java.security.MessageDigest;
public class AuthService {
public String hashPassword(String password) throws Exception {
// MD5 ist gebrochen - Rainbow Tables existieren für gängige Passwörter
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] hash = md.digest(password.getBytes());
return bytesToHex(hash);
}
// VERWUNDBAR: Anmeldedaten im Quellcode
private static final String API_KEY = "sk-live-12345abcdef";
private static final String DB_PASSWORD = "ProductionDBPass!";
}
// VERWUNDBAR: Anmeldedaten in localStorage gespeichert
function saveCredentials(username, password) {
// localStorage ist über XSS zugänglich!
localStorage.setItem('username', username);
localStorage.setItem('password', password); // Klartext-Passwort!
}
// VERWUNDBAR: Anmeldedaten in Umgebung ohne Schutz
const config = {
dbHost: process.env.DB_HOST,
dbUser: process.env.DB_USER,
dbPassword: process.env.DB_PASSWORD // Kann in Prozessliste sichtbar sein
};
// VERWUNDBAR: Hardcodierte Anmeldedaten
const apiKey = 'sk_live_51H7...'; // In Versionskontrolle committed!
Lösungscode
# SICHER: Ordnungsgemäßes Passwort-Hashing mit Argon2
from argon2 import PasswordHasher
from argon2.exceptions import VerifyMismatchError
import os
from cryptography.fernet import Fernet
ph = PasswordHasher(
time_cost=3, # Anzahl der Iterationen
memory_cost=65536, # Speicherverbrauch in KB
parallelism=4 # Parallele Threads
)
def create_user_safe(username, password):
conn = sqlite3.connect('users.db')
cursor = conn.cursor()
# Passwort mit Argon2 hashen - Salt automatisch enthalten
password_hash = ph.hash(password)
cursor.execute("INSERT INTO users (username, password_hash) VALUES (?, ?)",
(username, password_hash))
conn.commit()
def verify_password(stored_hash, provided_password):
try:
ph.verify(stored_hash, provided_password)
# Prüfen, ob Hash Rehashing benötigt (Parameter geändert)
if ph.check_needs_rehash(stored_hash):
return True, ph.hash(provided_password)
return True, None
except VerifyMismatchError:
return False, None
# SICHER: Verschlüsselte Anmeldedatenspeicherung
class SecureCredentialStore:
def __init__(self, key_file):
# Schlüssel sollte in Produktion in HSM oder sicherem Vault gespeichert sein
with open(key_file, 'rb') as f:
key = f.read()
self.fernet = Fernet(key)
def store_credential(self, name, credential):
encrypted = self.fernet.encrypt(credential.encode())
# Verschlüsselte Anmeldedaten speichern
self._save_to_secure_store(name, encrypted)
def get_credential(self, name):
encrypted = self._load_from_secure_store(name)
return self.fernet.decrypt(encrypted).decode()
// SICHER: Starkes Passwort-Hashing mit BCrypt
import org.mindrot.jbcrypt.BCrypt;
public class SecureAuthService {
private static final int BCRYPT_ROUNDS = 12;
public String hashPassword(String password) {
// BCrypt enthält Salt automatisch
return BCrypt.hashpw(password, BCrypt.gensalt(BCRYPT_ROUNDS));
}
public boolean verifyPassword(String password, String storedHash) {
return BCrypt.checkpw(password, storedHash);
}
}
// SICHER: Anmeldedaten aus sicherem Vault
import com.bettercloud.vault.Vault;
public class SecureConfig {
private final Vault vault;
public SecureConfig() {
VaultConfig config = new VaultConfig()
.address(System.getenv("VAULT_ADDR"))
.token(System.getenv("VAULT_TOKEN"))
.build();
this.vault = new Vault(config);
}
public String getApiKey() throws VaultException {
return vault.logical()
.read("secret/data/api-keys")
.getData()
.get("api_key");
}
public String getDbPassword() throws VaultException {
// Vault kann dynamische, kurzlebige Anmeldedaten bereitstellen
return vault.logical()
.read("database/creds/my-role")
.getData()
.get("password");
}
}
// SICHER: Niemals Anmeldedaten in localStorage speichern
// HTTP-only Cookies für Session-Tokens stattdessen verwenden
function setAuthToken(token) {
// Server setzt HTTP-only Cookie, nicht über JavaScript zugänglich
// fetch('/api/auth/token', { credentials: 'include' });
}
// SICHER: Umgebungsvariablen mit ordnungsgemäßem Schutz verwenden
const { SecretManagerServiceClient } = require('@google-cloud/secret-manager');
async function getCredentials() {
const client = new SecretManagerServiceClient();
// Secret aus Secret Manager des Cloud-Providers abrufen
const [version] = await client.accessSecretVersion({
name: 'projects/my-project/secrets/db-password/versions/latest',
});
return version.payload.data.toString();
}
// SICHER: Verschlüsselte Anmeldedatendatei mit ordnungsgemäßer Schlüsselverwaltung
const crypto = require('crypto');
const fs = require('fs');
class SecureCredentialManager {
constructor(keyPath) {
// Schlüssel aus sicherem Ort geladen (HSM, KMS, etc.)
this.key = fs.readFileSync(keyPath);
}
encrypt(credential) {
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv('aes-256-gcm', this.key, iv);
let encrypted = cipher.update(credential, 'utf8', 'hex');
encrypted += cipher.final('hex');
const authTag = cipher.getAuthTag();
return { iv: iv.toString('hex'), encrypted, authTag: authTag.toString('hex') };
}
decrypt(encryptedData) {
const decipher = crypto.createDecipheriv(
'aes-256-gcm',
this.key,
Buffer.from(encryptedData.iv, 'hex')
);
decipher.setAuthTag(Buffer.from(encryptedData.authTag, 'hex'));
let decrypted = decipher.update(encryptedData.encrypted, 'hex', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
}
}
Ausgenutzt in der Praxis
Apache Fineract Credential-Offenlegung (Apache, 2025)
CVE-2025-58130 in Apache Fineract bis 1.11.0 legt unzureichend geschützte Anmeldedaten offen, was unbefugten Zugriff auf Finanzdaten, Kundeninformationen und Transaktionssysteme in Mikrofinanz- und Fintech-Umgebungen ermöglicht, mit Potenzial für Betrug und DSGVO-Verstöße.
FortiOS LDAP-Anmeldedatendiebstahl (Fortinet, 2024-2025)
FG-IR-24-111 in FortiOS ermöglicht privilegierten Angreifern, LDAP-Anmeldedaten abzurufen, indem sie die LDAP-Serverkonfiguration auf angreiferkontrollierte Server umleiten, was Anmeldedaten-Abfangen durch Konfigurationsmanipulation demonstriert.
Elastic Kibana Crowdstrike-Anmeldedatenleck (Elastic, 2025)
CVE-2025-37728 in Kibana ermöglicht Angreifern mit geringen Privilegien den Zugriff auf zwischengespeicherte Crowdstrike-Anmeldedaten aus anderen Kibana-Spaces, was möglicherweise Sicherheitsüberwachung und Incident-Response-Fähigkeiten kompromittiert.
Tools zum Testen/Ausnutzen
-
TruffleHog — Geleakte Anmeldedaten im Code finden.
-
Hashcat — Passwort-Hash-Cracking.
-
CyberChef — Schwache Anmeldedaten-Kodierung dekodieren/entschlüsseln.
CVE-Beispiele
-
CVE-2025-58130 — Apache Fineract Anmeldedaten-Offenlegung.
-
CVE-2025-37728 — Elastic Kibana Anmeldedatenleck.
-
CVE-2024-45046 — Anmeldedaten-Offenlegungsschwachstelle.
Referenzen
-
MITRE. "CWE-522: Insufficiently Protected Credentials." https://cwe.mitre.org/data/definitions/522.html
-
OWASP. "Password Storage Cheat Sheet." https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html