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

AuswirkungDetails
ZugriffskontrolleBereich: 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ätBereich: 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

  1. MITRE Corporation. "CWE-501: Trust Boundary Violation." https://cwe.mitre.org/data/definitions/501.html
  2. OWASP. "Session Management Cheat Sheet."
  3. CERT. "Trust Boundaries and Data Validation."