Klartext-Speicherung sensibler Informationen in einem Cookie
Beschreibung
Klartext-Speicherung sensibler Informationen in einem Cookie ist eine Schwachstelle, die auftritt, wenn ein Produkt sensible Informationen im Klartext in Browser-Cookies speichert. Cookies werden auf dem Computer des Clients gespeichert und mit jeder HTTP-Anfrage übertragen, was sie für Benutzer, Browser-Erweiterungen und potenziell für Angreifer durch XSS-Schwachstellen oder physischen Zugriff auf das Gerät zugänglich macht. Sensible Informationen, die in Klartext-Cookies gespeichert sind, können leicht gelesen und möglicherweise modifiziert werden. Selbst kodierte Daten (wie Base64) bieten keine echte Sicherheit, da Angreifer leicht die Kodierungsmethode bestimmen und die Informationen dekodieren können.
Risiko
Klartext-Cookie-Speicherung exponiert sensible Daten durch mehrere Angriffsvektoren. Cross-Site-Scripting (XSS)-Schwachstellen ermöglichen Angreifern, Cookies remote zu stehlen. Physischer Zugriff auf ein Gerät ermöglicht direktes Lesen von Cookie-Dateien. Browser-Erweiterungen können auf Cookie-Daten zugreifen. Netzwerk-Angreifer können über unverschlüsselte HTTP-Verbindungen übertragene Cookies abfangen. Man-in-the-Middle-Angriffe können Cookies erfassen, selbst wenn die initiale Verbindung HTTPS verwendet, falls Cookie-Sicherheitsflags nicht gesetzt sind. Das Risiko wird verstärkt, weil Cookies über Browser-Sitzungen hinweg bestehen und auch nach dem Logout der Benutzer zugänglich bleiben können, wenn sie nicht ordnungsgemäß ablaufen. Exponierte Anmeldedaten ermöglichen Kontoübernahme, während exponierte Session-Daten Session-Hijacking ermöglichen können.
Lösung
Speichern Sie niemals sensible Informationen direkt in Cookies. Verwenden Sie für Authentifizierung serverseitige Sessions mit nur einer sicheren, zufälligen Session-ID im Cookie. Wenn Cookies Daten enthalten müssen, verschlüsseln Sie sie serverseitig mit authentifizierter Verschlüsselung vor der Speicherung und entschlüsseln Sie nur auf dem Server. Setzen Sie das HttpOnly-Flag, um JavaScript-Zugriff zu verhindern und XSS-basierten Cookie-Diebstahl zu mildern. Setzen Sie das Secure-Flag, um sicherzustellen, dass Cookies nur über HTTPS übertragen werden. Verwenden Sie das SameSite-Attribut, um Cross-Site-Request-Forgery zu verhindern. Implementieren Sie kurze Cookie-Ablaufzeiten für sensible Daten. Speichern Sie sensible Benutzerdaten serverseitig und referenzieren Sie sie über Session-IDs, anstatt sie in Cookies aufzunehmen. Speichern Sie niemals Anmeldedaten, Finanzdaten oder persönliche Informationen in Cookies.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Vertraulichkeit | Bereich: Vertraulichkeit Angreifer können sensible Informationen, die in Cookies gespeichert sind, durch verschiedene Methoden lesen, einschließlich XSS-Angriffe, physischen Zugriff, Browser-Erweiterungen oder Netzwerkabfangen. |
| Authentifizierung, Zugriffskontrolle | Bereich: Authentifizierung, Zugriffskontrolle Exponierte Anmeldedaten ermöglichen Kontoübernahme. Exponierte Session-Daten ermöglichen Session-Hijacking. Angreifer können Benutzer imitieren und auf geschützte Ressourcen zugreifen. |
Beispielcode
Anfälliger Code (Java/PHP)
Die folgenden Beispiele demonstrieren Klartext-Cookie-Speicherungs-Schwachstellen:
// Anfällig: Account-ID in Klartext-Cookie speichern
import javax.servlet.http.*;
public class VulnerableCookieStorage extends HttpServlet {
protected void doPost(HttpServletRequest request,
HttpServletResponse response) {
String accountId = request.getParameter("account");
// Anfällig: Klartext-Account-ID im Cookie
Cookie cookie = new Cookie("userAccountID", accountId);
cookie.setMaxAge(3600); // 1 Stunde
response.addCookie(cookie);
// Angreifer kann Account-ID lesen und modifizieren!
}
// Anfällig: Anmeldedaten in Cookie speichern
public void persistLogin(HttpServletResponse response,
String username, String password) {
// Anfällig: Klartext-Benutzername im Cookie
Cookie userCookie = new Cookie("username", username);
response.addCookie(userCookie);
// Extrem anfällig: Klartext-Passwort im Cookie!
Cookie passCookie = new Cookie("password", password);
response.addCookie(passCookie);
// Keine HttpOnly-, Secure- oder SameSite-Flags!
}
// Anfällig: Rolle/Berechtigungen in Cookie speichern
public void setUserRole(HttpServletResponse response, String role) {
// Anfällig: Benutzer kann modifizieren um Admin-Zugriff zu erlangen
Cookie roleCookie = new Cookie("userRole", role);
response.addCookie(roleCookie);
// Angreifer ändert Cookie zu "admin" und erlangt Privilegien!
}
}
<?php
// Anfällig: Login-Anmeldedaten in Klartext-Cookie speichern
function persistLogin($username, $password) {
// Anfällig: Klartext-Anmeldedaten im Cookie
$data = array("username" => $username, "password" => $password);
setcookie("userdata", json_encode($data), time() + 3600);
// Jeder mit Cookie-Zugriff erhält Anmeldedaten!
}
// Anfällig: Sensible Benutzerdaten in Cookie speichern
function setUserSession($userData) {
// Anfällig: PII in Klartext-Cookie
$sessionData = array(
"user_id" => $userData['id'],
"email" => $userData['email'],
"ssn" => $userData['ssn'], // Sozialversicherungsnummer im Cookie!
"credit_card" => $userData['card'] // Kreditkarte im Cookie!
);
setcookie("session", base64_encode(json_encode($sessionData)));
// Base64 ist KEINE Verschlüsselung - leicht dekodierbar!
}
// Anfällig: Authentifizierungstoken ohne Sicherheitsflags speichern
function setAuthToken($token) {
// Anfällig: Fehlende Sicherheitsflags
setcookie(
"auth_token",
$token,
time() + 86400,
"/"
// Fehlend: secure, httponly, samesite Flags!
);
}
?>
# Anfällig: Flask Klartext-Cookie-Speicherung
from flask import Flask, request, make_response
app = Flask(__name__)
@app.route('/login', methods=['POST'])
def login():
username = request.form.get('username')
password = request.form.get('password')
if authenticate(username, password):
response = make_response(redirect('/dashboard'))
# Anfällig: Klartext-Anmeldedaten in Cookies
response.set_cookie('username', username)
response.set_cookie('user_password', password) # Passwort im Cookie!
# Anfällig: Sensible Daten ohne Sicherheitsflags
response.set_cookie('user_id', str(get_user_id(username)))
response.set_cookie('user_role', get_user_role(username))
return response
return redirect('/login?error=1')
Korrigierter Code (Java/PHP)
// Korrigiert: Sichere Session-Handhabung ohne sensible Cookie-Daten
import javax.servlet.http.*;
import javax.crypto.*;
import java.security.SecureRandom;
import java.util.Base64;
public class SecureCookieStorage extends HttpServlet {
private final SecretKey encryptionKey;
private final Map<String, SessionData> serverSessions = new ConcurrentHashMap<>();
protected void doPost(HttpServletRequest request,
HttpServletResponse response) {
String username = request.getParameter("username");
// Korrigiert: Serverseitige Session erstellen
String sessionId = generateSecureSessionId();
serverSessions.put(sessionId, new SessionData(username));
// Korrigiert: Nur Session-ID im Cookie speichern, nicht Account-Daten
Cookie sessionCookie = new Cookie("session_id", sessionId);
sessionCookie.setHttpOnly(true); // Korrigiert: Kein JavaScript-Zugriff
sessionCookie.setSecure(true); // Korrigiert: Nur HTTPS
sessionCookie.setMaxAge(3600);
sessionCookie.setPath("/");
// Korrigiert: SameSite-Attribut setzen (erfordert Servlet 4.0+ oder Header)
response.setHeader("Set-Cookie",
sessionCookie.getName() + "=" + sessionCookie.getValue() +
"; HttpOnly; Secure; SameSite=Strict; Path=/; Max-Age=3600");
response.addCookie(sessionCookie);
}
// Korrigiert: Serverseitige Session-Abfrage
public SessionData getSession(HttpServletRequest request) {
Cookie[] cookies = request.getCookies();
if (cookies == null) return null;
for (Cookie cookie : cookies) {
if ("session_id".equals(cookie.getName())) {
return serverSessions.get(cookie.getValue());
}
}
return null;
}
// Korrigiert: Falls Cookie-Daten nötig, verschlüsseln
public void setEncryptedCookie(HttpServletResponse response,
String name, String value) {
String encrypted = encrypt(value);
Cookie cookie = new Cookie(name, encrypted);
cookie.setHttpOnly(true);
cookie.setSecure(true);
cookie.setMaxAge(3600);
response.addCookie(cookie);
}
private String encrypt(String data) {
try {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
byte[] iv = new byte[12];
SecureRandom.getInstanceStrong().nextBytes(iv);
cipher.init(Cipher.ENCRYPT_MODE, encryptionKey, new GCMParameterSpec(128, iv));
byte[] encrypted = cipher.doFinal(data.getBytes());
byte[] combined = new byte[iv.length + encrypted.length];
System.arraycopy(iv, 0, combined, 0, iv.length);
System.arraycopy(encrypted, 0, combined, iv.length, encrypted.length);
return Base64.getUrlEncoder().encodeToString(combined);
} catch (Exception e) {
throw new RuntimeException("Verschlüsselung fehlgeschlagen", e);
}
}
private String generateSecureSessionId() {
byte[] bytes = new byte[32];
new SecureRandom().nextBytes(bytes);
return Base64.getUrlEncoder().encodeToString(bytes);
}
}
<?php
// Korrigiert: Sichere Session-Handhabung
function secureLogin($userId) {
// Korrigiert: PHP-Sessions anstelle von Credential-Cookies verwenden
session_start();
session_regenerate_id(true); // Fixation verhindern
// Korrigiert: Benutzerreferenz in serverseitiger Session speichern
$_SESSION['user_id'] = $userId;
$_SESSION['created_at'] = time();
$_SESSION['ip'] = $_SERVER['REMOTE_ADDR'];
// Korrigiert: Sichere Session-Cookie konfigurieren
$cookieParams = [
'lifetime' => 3600,
'path' => '/',
'secure' => true, // Nur HTTPS
'httponly' => true, // Kein JavaScript-Zugriff
'samesite' => 'Strict' // CSRF-Schutz
];
session_set_cookie_params($cookieParams);
// Keine sensiblen Daten in Cookies!
}
// Korrigiert: Verschlüsseltes Cookie falls Daten clientseitig gespeichert werden müssen
function setEncryptedCookie($name, $data) {
$key = getEncryptionKey(); // Aus sicherem Speicher abrufen
$iv = random_bytes(16);
$encrypted = openssl_encrypt(
json_encode($data),
'AES-256-GCM',
$key,
0,
$iv,
$tag
);
$cookieValue = base64_encode($iv . $tag . $encrypted);
setcookie(
$name,
$cookieValue,
[
'expires' => time() + 3600,
'path' => '/',
'secure' => true,
'httponly' => true,
'samesite' => 'Strict'
]
);
}
function getEncryptedCookie($name) {
if (!isset($_COOKIE[$name])) {
return null;
}
$key = getEncryptionKey();
$data = base64_decode($_COOKIE[$name]);
$iv = substr($data, 0, 16);
$tag = substr($data, 16, 16);
$encrypted = substr($data, 32);
$decrypted = openssl_decrypt(
$encrypted,
'AES-256-GCM',
$key,
0,
$iv,
$tag
);
return json_decode($decrypted, true);
}
?>
# Korrigiert: Sichere Flask-Session-Handhabung
from flask import Flask, session, redirect, request, make_response
from flask_session import Session
import secrets
app = Flask(__name__)
app.config['SECRET_KEY'] = secrets.token_bytes(32)
app.config['SESSION_TYPE'] = 'redis' # Serverseitige Session
app.config['SESSION_COOKIE_SECURE'] = True
app.config['SESSION_COOKIE_HTTPONLY'] = True
app.config['SESSION_COOKIE_SAMESITE'] = 'Strict'
Session(app)
@app.route('/login', methods=['POST'])
def login():
username = request.form.get('username')
password = request.form.get('password')
if authenticate(username, password):
# Korrigiert: Serverseitige Session-Speicherung
session.regenerate() # Fixation verhindern
session['user_id'] = get_user_id(username)
session['username'] = username
session['authenticated'] = True
session['created_at'] = time.time()
# Korrigiert: Keine sensiblen Daten in Cookies
# Nur Session-ID wird übertragen
return redirect('/dashboard')
return redirect('/login?error=1')
@app.route('/dashboard')
def dashboard():
# Korrigiert: Session serverseitig verifizieren
if not session.get('authenticated'):
return redirect('/login')
# Benutzerdaten aus serverseitiger Session holen
user_id = session.get('user_id')
return render_template('dashboard.html', user=get_user(user_id))
Die Korrektur verwendet serverseitige Sessions mit sicheren Session-Cookies und ordnungsgemäßen Sicherheitsflags.
Ausgenutzt in der Praxis
Admin-Passwort-Cookie-Exposition (Webanwendungen, 2002)
CVE-2002-1800 dokumentierte eine Webanwendung, die das Administrator-Passwort in einem Klartext-Cookie speicherte, was vollständigen administrativen Zugangsdiebstahl ermöglichte.
Standard-Konfiguration Credential-Exposition (Enterprise-Software, 2001)
CVE-2001-1537 und CVE-2001-1536 dokumentierten Produkte mit Standardkonfigurationen, die Benutzernamen und Passwörter in Klartext-Cookies speicherten.
Tools zum Testen/Ausnutzen
-
Browser Developer Tools — Integrierte Tools zum Anzeigen und Modifizieren von Cookies.
-
Burp Suite — Web-Sicherheitstool zum Abfangen und Analysieren von Cookies.
-
OWASP ZAP — Open-Source-Scanner, der unsichere Cookie-Einstellungen identifiziert.
CVE-Beispiele
-
CVE-2002-1800 — Admin-Passwort in Klartext-Cookie gespeichert.
-
CVE-2001-1537 — Klartext-Benutzernamen/Passwörter in Cookies.
-
CVE-2001-1536 — Benutzernamen/Passwörter in Klartext-Cookies.
-
CVE-2005-2160 — Authentifizierungsinformationen unverschlüsselt im Cookie gespeichert.
Referenzen
-
MITRE Corporation. "CWE-315: Cleartext Storage of Sensitive Information in a Cookie." Common Weakness Enumeration. https://cwe.mitre.org/data/definitions/315.html
-
OWASP Foundation. "Session Management Cheat Sheet." https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html
-
RFC 6265. "HTTP State Management Mechanism." https://tools.ietf.org/html/rfc6265