Verletzung der Vertrauensgrenze
Beschreibung
Verletzung der Vertrauensgrenze ist eine Schwachstelle, bei der ein Produkt vertrauenswürdige und nicht vertrauenswürdige Daten in derselben Datenstruktur oder strukturierten Nachricht vermischt. Eine Vertrauensgrenze repräsentiert eine konzeptionelle Linie, die nicht vertrauenswürdige Daten von vertrauenswürdigen Daten trennt, wobei Validierungslogik es Daten ermöglicht, diese Grenze sicher zu überschreiten. Wenn Programme diese Unterscheidung verwischen, indem sie validierte und nicht validierte Daten in gemeinsamen Strukturen wie Session-Objekten, Datenbanken oder Nachrichtenwarteschlangen kombinieren, können Entwickler versehentlich Daten vertrauen, die nicht ordnungsgemäß validiert wurden, was zu Sicherheitsschwachstellen führt.
Risiko
Das Vermischen von vertrauenswürdigen und nicht vertrauenswürdigen Daten schafft schwerwiegende Sicherheitsrisiken, da Entwickler die Fähigkeit verlieren, zu unterscheiden, welche Daten validiert wurden. Benutzereingaben, die neben servergernerierten Werten in Session-Objekten gespeichert werden, können bei nachfolgenden Operationen fälschlicherweise als vertrauenswürdig behandelt werden. Nicht vertrauenswürdige Daten, die in vertrauenswürdige Nachrichtenwarteschlangen injiziert werden, können privilegierte Operationen auslösen. Daten, die in gemeinsamen Caches oder Datenbanken ohne klare Herkunftsverfolgung gespeichert werden, können für sicherheitskritische Entscheidungen verwendet werden. Diese Schwachstelle ermöglicht verschiedene Angriffe einschließlich Privilegieneskalation, Injection-Angriffe und Umgehung von Sicherheitskontrollen, wenn nicht vertrauenswürdige Daten so konsumiert werden, als wären sie vertrauenswürdig.
Lösung
Etablieren und pflegen Sie gut definierte Vertrauensgrenzen in der gesamten Anwendung. Speichern Sie vertrauenswürdige und nicht vertrauenswürdige Daten in separaten Datenstrukturen mit klaren Namenskonventionen oder Typunterscheidungen. Validieren und bereinigen Sie alle Daten, bevor sie von nicht vertrauenswürdigen in vertrauenswürdige Kontexte wechseln. Verwenden Sie Typsysteme oder Wrapper-Klassen, um validierte von nicht validierten Daten zu unterscheiden. Implementieren Sie Validierungs-Checkpoints an Vertrauensgrenzen, anstatt sich auf implizites Vertrauen zu verlassen. Dokumentieren Sie Vertrauensannahmen für alle Datenstrukturen. Speichern Sie niemals benutzerbereitgestellte Daten in Session-Objekten ohne explizite Validierung und klare Markierung ihrer Herkunft.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Zugriffskontrolle | Bereich: Zugriffskontrolle Schutzmechanismus umgehen - Sicherheitsvorkehrungen können durch Manipulation gemischter vertrauenswürdiger/nicht vertrauenswürdiger Datenquellen umgangen werden, was Angreifern ermöglicht, bösartige Daten zu injizieren, die später als vertrauenswürdig behandelt werden. |
| Integrität | Bereich: Integrität Anwendungsdaten modifizieren - Nicht vertrauenswürdige Daten, die mit vertrauenswürdigen Daten vermischt werden, können den vertrauenswürdigen Datenspeicher korrumpieren, was zu falschen Sicherheitsentscheidungen oder Datenkorruption führt. |
Beispielcode
Verwundbarer Code
// Verwundbar: Nicht vertrauenswürdige Eingabe ohne Validierung in Session speichern
import javax.servlet.http.*;
public class VulnerableLoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request,
HttpServletResponse response) {
String username = request.getParameter("usrname");
HttpSession session = request.getSession();
// Verwundbar: Nicht vertrauenswürdige Eingabe direkt in Session gespeichert
// Späterer Code könnte dies als validiert/vertrauenswürdig behandeln
if (session.getAttribute("ATTR_USR") == null) {
session.setAttribute("ATTR_USR", username);
}
// Verwundbar: Nicht vertrauenswürdige Rolle aus Request in Session gespeichert
String role = request.getParameter("role");
session.setAttribute("USER_ROLE", role);
// Authentifizierung erfolgt später, aber Benutzername ist bereits "vertrauenswürdig"
if (authenticateUser(username, request.getParameter("password"))) {
// Selbst wenn Auth fehlschlägt, ist Benutzername in Session
}
}
}
// Späterer Code vertraut den Session-Daten
public class VulnerableProfileServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) {
HttpSession session = request.getSession();
// Verwundbar: Nimmt an, dass Benutzername validiert wurde
String username = (String) session.getAttribute("ATTR_USR");
// Verwundbar: Verwendet nicht vertrauenswürdige Rolle für Autorisierung
String role = (String) session.getAttribute("USER_ROLE");
if ("admin".equals(role)) {
// Angreifer kann role=admin im initialen Request setzen
showAdminPanel(response);
}
// Verwundbar: Benutzername in SQL ohne Validierung verwendet
// (nimmt an, dass Session-Daten sicher sind)
String query = "SELECT * FROM users WHERE name = '" + username + "'";
}
}
// Verwundbar: Vermischung vertrauenswürdiger und nicht vertrauenswürdiger Daten in derselben Map
public class VulnerableDataProcessor {
// Einzelne Map für alle Daten - keine Unterscheidung des Vertrauens
private Map<String, Object> dataStore = new HashMap<>();
public void processRequest(HttpServletRequest request) {
// Servergenrierte vertrauenswürdige Daten
dataStore.put("timestamp", System.currentTimeMillis());
dataStore.put("serverIP", getServerIP());
dataStore.put("sessionId", generateSecureSessionId());
// Verwundbar: Nicht vertrauenswürdige Benutzereingabe mit vertrauenswürdigen Daten vermischt
dataStore.put("username", request.getParameter("username"));
dataStore.put("email", request.getParameter("email"));
dataStore.put("preference", request.getParameter("pref"));
}
public void processData() {
// Keine Möglichkeit zu wissen, welche Daten vertrauenswürdig vs nicht vertrauenswürdig sind
String username = (String) dataStore.get("username"); // Nicht vertrauenswürdig!
Long timestamp = (Long) dataStore.get("timestamp"); // Vertrauenswürdig
// Entwickler könnte vergessen, dass username nicht vertrauenswürdig ist
log("Benutzer " + username + " Zugriff um " + timestamp); // Log-Injection!
}
}
// Verwundbar: Nachrichtenwarteschlange mischt Vertrauensstufen
public class VulnerableMessageProcessor {
public void processMessage(Message message) {
// Verwundbar: Keine Unterscheidung zwischen System- und Benutzernachrichten
String messageType = message.getHeader("type");
String payload = message.getBody();
// Benutzer könnte type=ADMIN_COMMAND injizieren
if ("ADMIN_COMMAND".equals(messageType)) {
executeAdminCommand(payload); // Gefährlich!
}
}
public void queueUserMessage(String userInput) {
Message message = new Message();
message.setHeader("type", "USER_MESSAGE");
message.setBody(userInput);
// Benutzer kann die Nachricht manipulieren, bevor sie eingereiht wird
messageQueue.add(message);
}
}
# Verwundbar: Python-Beispiel mit gemischten Vertrauensstufen
from flask import Flask, request, session
app = Flask(__name__)
@app.route('/login', methods=['POST'])
def vulnerable_login():
# Verwundbar: Nicht vertrauenswürdige Daten vor Validierung speichern
session['username'] = request.form['username']
session['preferred_language'] = request.form['lang']
# Vom Benutzer bereitgestellte Rolle direkt gespeichert
session['role'] = request.form.get('role', 'user')
# Später Anmeldedaten validieren (aber Daten bereits in Session)
if check_credentials(request.form['username'], request.form['password']):
session['authenticated'] = True
else:
session['authenticated'] = False
return redirect('/dashboard')
@app.route('/admin')
def vulnerable_admin():
# Verwundbar: Session-Daten ohne Überprüfung vertrauen
if session.get('role') == 'admin':
# Angreifer hat role=admin beim Login gesetzt
return render_admin_panel()
return "Zugriff verweigert"
# Verwundbar: Gemischte Daten in einzelnem Dictionary
class VulnerableUserData:
def __init__(self):
self.data = {}
def set_system_data(self, user_id):
# Vertrauenswürdige systemgenerierte Daten
self.data['created_at'] = datetime.now()
self.data['internal_id'] = generate_uuid()
def set_user_data(self, form_data):
# Nicht vertrauenswürdige Benutzereingabe mit Systemdaten vermischt
self.data['name'] = form_data['name']
self.data['bio'] = form_data['bio'] # Könnte XSS enthalten
Lösungscode
// Behoben: Klare Trennung von vertrauenswürdigen und nicht vertrauenswürdigen Daten
import javax.servlet.http.*;
public class SecureLoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request,
HttpServletResponse response) {
String username = request.getParameter("usrname");
String password = request.getParameter("password");
// Behoben: VOR dem Speichern in Session validieren
if (!isValidUsername(username)) {
response.sendError(400, "Ungültiges Benutzernamenformat");
return;
}
// Behoben: VOR dem Speichern von Benutzerdaten authentifizieren
User authenticatedUser = authenticateUser(username, password);
if (authenticatedUser == null) {
response.sendError(401, "Authentifizierung fehlgeschlagen");
return;
}
HttpSession session = request.getSession(true);
// Behoben: Validierte, serververifizierte Daten speichern
// Typisierter Wrapper zur Anzeige des Vertrauensniveaus verwenden
session.setAttribute("USER", new TrustedUser(
authenticatedUser.getId(),
authenticatedUser.getUsername(),
authenticatedUser.getRoles() // Rollen aus Datenbank, nicht Request
));
// Behoben: Session explizit als authentifiziert markieren
session.setAttribute("AUTHENTICATED", Boolean.TRUE);
}
private boolean isValidUsername(String username) {
return username != null &&
username.matches("^[a-zA-Z0-9_]{3,20}$");
}
}
// Behoben: Typisierter Wrapper, der Vertrauensstatus anzeigt
public final class TrustedUser {
private final String id;
private final String username;
private final Set<String> roles;
private final Instant validatedAt;
// Kann nur mit validierten Daten erstellt werden
public TrustedUser(String id, String username, Set<String> roles) {
this.id = Objects.requireNonNull(id);
this.username = Objects.requireNonNull(username);
this.roles = Collections.unmodifiableSet(new HashSet<>(roles));
this.validatedAt = Instant.now();
}
// Nur unveränderliche Getter
public String getId() { return id; }
public String getUsername() { return username; }
public Set<String> getRoles() { return roles; }
public Instant getValidatedAt() { return validatedAt; }
}
// Behoben: Profil-Servlet mit typisierten vertrauenswürdigen Daten
public class SecureProfileServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) {
HttpSession session = request.getSession(false);
if (session == null) {
response.sendError(401, "Nicht authentifiziert");
return;
}
// Behoben: Typisiertes Objekt verwenden - Compiler erzwingt Vertrauen
TrustedUser user = (TrustedUser) session.getAttribute("USER");
Boolean authenticated = (Boolean) session.getAttribute("AUTHENTICATED");
if (user == null || !Boolean.TRUE.equals(authenticated)) {
response.sendError(401, "Nicht authentifiziert");
return;
}
// Behoben: Rollen stammen aus vertrauenswürdiger Quelle (Datenbank)
if (user.getRoles().contains("ADMIN")) {
showAdminPanel(response);
}
// Behoben: Parametrisierte Abfrage mit validiertem Benutzernamen verwenden
String query = "SELECT * FROM users WHERE id = ?";
// user.getId() mit Prepared Statement verwenden
}
}
// Behoben: Separate Datenspeicher für verschiedene Vertrauensstufen
public class SecureDataProcessor {
// Behoben: Separate Strukturen für verschiedene Vertrauensstufen
private final TrustedData trustedData = new TrustedData();
private final UntrustedInput untrustedInput = new UntrustedInput();
public void processRequest(HttpServletRequest request) {
// Vertrauenswürdige Daten - vom Server generiert
trustedData.setTimestamp(System.currentTimeMillis());
trustedData.setServerIP(getServerIP());
trustedData.setSessionId(generateSecureSessionId());
// Behoben: Nicht vertrauenswürdige Daten separat halten
untrustedInput.setUsername(request.getParameter("username"));
untrustedInput.setEmail(request.getParameter("email"));
untrustedInput.setPreference(request.getParameter("pref"));
}
public void processData() {
// Behoben: Vor Verwendung nicht vertrauenswürdiger Daten validieren
String validatedUsername = validateAndSanitize(
untrustedInput.getUsername()
);
Long timestamp = trustedData.getTimestamp(); // Immer sicher
// Behoben: Vor Logging bereinigt
log("Benutzer " + escapeForLog(validatedUsername) + " Zugriff um " + timestamp);
}
// Behoben: Explizite Grenzüberschreitung der Validierung
public TrustedUserData promoteToTrusted(UntrustedInput input)
throws ValidationException {
// Alle Validierung erfolgt hier an der Vertrauensgrenze
String validUsername = validateUsername(input.getUsername());
String validEmail = validateEmail(input.getEmail());
// Erst nach Validierung vertrauenswürdiges Objekt erstellen
return new TrustedUserData(validUsername, validEmail);
}
}
// Behoben: Typisierte Wrapper erzwingen Vertrauensunterscheidung
public final class UntrustedInput {
private String username;
private String email;
private String preference;
// Setter akzeptieren jeden String
public void setUsername(String username) { this.username = username; }
public void setEmail(String email) { this.email = email; }
public void setPreference(String pref) { this.preference = pref; }
// Getter - Aufrufer weiß, dass dies nicht vertrauenswürdig ist
public String getUsername() { return username; }
public String getEmail() { return email; }
public String getPreference() { return preference; }
}
public final class TrustedUserData {
private final String username;
private final String email;
// Konstruktor akzeptiert nur validierte Daten
TrustedUserData(String validatedUsername, String validatedEmail) {
this.username = validatedUsername;
this.email = validatedEmail;
}
public String getUsername() { return username; }
public String getEmail() { return email; }
}
# Behoben: Klare Vertrauensgrenzen in Python
from flask import Flask, request, session
from dataclasses import dataclass
from typing import Set, Optional
import re
app = Flask(__name__)
@dataclass(frozen=True) # Unveränderlich
class TrustedUser:
"""Repräsentiert validierte, vertrauenswürdige Benutzerdaten."""
user_id: str
username: str
roles: frozenset
@dataclass
class UntrustedInput:
"""Wrapper für nicht vertrauenswürdige Benutzereingabe."""
value: str
source: str = "user"
def validate_username(untrusted: UntrustedInput) -> str:
"""Validierungsgrenze - konvertiert nicht vertrauenswürdig zu vertrauenswürdig."""
if not untrusted.value:
raise ValueError("Benutzername erforderlich")
if not re.match(r'^[a-zA-Z0-9_]{3,20}$', untrusted.value):
raise ValueError("Ungültiges Benutzernamenformat")
return untrusted.value # Jetzt validiert
@app.route('/login', methods=['POST'])
def secure_login():
# Behoben: Nicht vertrauenswürdige Eingabe explizit wrappen
username_input = UntrustedInput(request.form.get('username', ''))
password_input = UntrustedInput(request.form.get('password', ''))
try:
# Behoben: An Vertrauensgrenze validieren
validated_username = validate_username(username_input)
except ValueError as e:
return f"Ungültige Eingabe: {e}", 400
# Behoben: Authentifizieren bevor irgendetwas gespeichert wird
user = authenticate(validated_username, password_input.value)
if user is None:
return "Authentifizierung fehlgeschlagen", 401
# Behoben: Nur vertrauenswürdige, validierte Daten speichern
trusted_user = TrustedUser(
user_id=user.id,
username=user.username,
roles=frozenset(user.roles) # Rollen aus Datenbank
)
session['user'] = trusted_user
session['authenticated'] = True
return redirect('/dashboard')
@app.route('/admin')
def secure_admin():
# Behoben: Typisiertes vertrauenswürdiges Objekt prüfen
user = session.get('user')
if not isinstance(user, TrustedUser):
return "Nicht authentifiziert", 401
if not session.get('authenticated'):
return "Nicht authentifiziert", 401
# Behoben: Rollen stammen aus vertrauenswürdiger Quelle
if 'admin' in user.roles:
return render_admin_panel()
return "Zugriff verweigert", 403
CVE-Beispiele
Keine spezifischen CVEs sind in der MITRE-Datenbank für diese CWE aufgeführt. Das Schwachstellenmuster ist jedoch dokumentiert in:
- OWASP A04:2021 - Unsicheres Design
- Zahlreiche Session-Manipulations- und Privilegieneskalations-Schwachstellen
Referenzen
- MITRE Corporation. "CWE-501: Trust Boundary Violation." https://cwe.mitre.org/data/definitions/501.html
- OWASP. "Session Management Cheat Sheet."
- CERT. "Trust Boundaries and Data Validation."