Unvollständiger Vergleich mit fehlenden Faktoren

Beschreibung

Unvollständiger Vergleich mit fehlenden Faktoren tritt auf, wenn ein Produkt einen Vergleich zwischen Entitäten durchführt, aber nicht alle relevanten Faktoren oder Attribute einbezieht, die für einen vollständigen und sicheren Vergleich notwendig sind. Dies kann zu falschen Gleichheits- oder Ungleichheitsbestimmungen führen und Sicherheitskontrollen umgehen. Häufige Beispiele sind der Vergleich nur eines Teils eines Passworts, die Prüfung nur einer Teilmenge von Authentifizierungstoken oder die Validierung nur einiger Felder eines Zertifikats. Die fehlenden Faktoren mögen unwichtig erscheinen, können aber für Sicherheitsentscheidungen entscheidend sein.

Risiko

Diese Schwachstelle kann zu Authentifizierungsumgehungen, Autorisierungsfehlern und Datenintegritätsproblemen führen. Angreifer können Eingaben erstellen, die unvollständige Vergleiche erfüllen, während sie sich in nicht geprüften Attributen unterscheiden. Passwortvergleiche, die nur die ersten N Zeichen prüfen, erlauben jedes Passwort mit übereinstimmenden Präfixen. Zertifikatsvalidierung, die bestimmte Felder überspringt, kann betrügerische Zertifikate akzeptieren. Session-Token-Vergleiche, die Entropieprüfungen auslassen, können für Brute-Force anfällig sein. Die Schwere hängt davon ab, welche Sicherheitsentscheidungen auf dem fehlerhaften Vergleich basieren.

Lösung

Stellen Sie sicher, dass alle sicherheitsrelevanten Attribute in Vergleichen einbezogen werden. Vergleichen Sie bei Passwörtern immer die vollständigen Werte mit konstant-zeitlichen Vergleichsfunktionen. Validieren Sie bei Zertifikaten alle relevanten Felder einschließlich Aussteller, Gültigkeitszeitraum, Schlüsselverwendung und die gesamte Kette. Vergleichen Sie bei Token und Bezeichnern alle Bytes. Verwenden Sie gut getestete Vergleichsfunktionen aus Sicherheitsbibliotheken anstatt eigene Vergleiche zu implementieren. Dokumentieren Sie, welche Faktoren verglichen werden, und begründen Sie etwaige Ausschlusse. Testen Sie Vergleiche mit Eingaben, die sich nur in ausgeschlossenen Faktoren unterscheiden.

Häufige Auswirkungen

AuswirkungDetails
ZugriffskontrolleBereich: Zugriffskontrolle

Schutzmechanismus umgehen - Unvollständige Vergleiche können unautorisierten Zugriff ermöglichen, wenn sicherheitskritische Unterschiede nicht geprüft werden.
IntegritätBereich: Integrität

Anwendungsdaten ändern - Falsche Gleichheitsbestimmungen können zu Datenkorruption oder unautorisierten Änderungen führen.
VertraulichkeitBereich: Vertraulichkeit

Anwendungsdaten lesen - Authentifizierungsumgehungen durch unvollständige Vergleiche können sensible Daten offenlegen.

Beispielcode und Lösung

Verwundbarer Code

// Verwundbar: Nur erste N Zeichen des Passworts vergleichen
#include <string.h>

int verwundbarer_passwort_check(const char *eingabe, const char *gespeichert) {
    // Verwundbar: Prüft nur erste 8 Zeichen
    // "passwort123" und "passwort_irgendwas" würden übereinstimmen
    return strncmp(eingabe, gespeichert, 8) == 0;
}

// Angreifer kann jedes Passwort verwenden, das mit den gleichen 8 Zeichen beginnt
// Verwundbar: Unvollständiger Token-Vergleich
public class VerwundbarerTokenValidator {

    public boolean validateToken(String token) {
        // Verwundbar: Prüft nur Präfix und verifiziert Signatur nicht
        String[] parts = token.split("\\.");

        if (parts.length != 3) {
            return false;
        }

        // Validiert nur Header-Format
        String header = parts[0];
        if (!header.startsWith("eyJ")) {  // Base64 von {"
            return false;
        }

        // Verwundbar: Überspringt Signaturverifizierung (parts[2])!
        // Angreifer kann Payload ohne Erkennung ändern

        return true;
    }
}
# Verwundbar: Unvollständige Zertifikatsvalidierung
import ssl

def verwundbare_zertifikat_validierung(cert):
    # Verwundbar: Prüft nur einige Felder

    # Aussteller prüfen
    if cert.get_issuer().CN != "Vertrauenswürdige CA":
        return False

    # Gültigkeitszeitraum prüfen
    if cert.has_expired():
        return False

    # Verwundbar: Fehlende Prüfungen:
    # - Zertifikatsketten-Validierung
    # - Schlüsselverwendungs-Einschränkungen
    # - Subject Alternative Names
    # - Widerrufsstatus (CRL/OCSP)
    # - Signaturverifizierung

    return True
// Verwundbar: Unvollständiger API-Schlüssel-Vergleich
function verwundbareApiKeyValidierung(bereitgestellterKey, gespeicherterKey) {
    // Verwundbar: Vergleicht nur Länge und erste Zeichen
    if (bereitgestellterKey.length !== gespeicherterKey.length) {
        return false;
    }

    // Verwundbar: Prüft nur erste 16 Zeichen
    const präfix = bereitgestellterKey.substring(0, 16);
    const gespeichertesPräfix = gespeicherterKey.substring(0, 16);

    return präfix === gespeichertesPräfix;

    // Angreifer kann jeden Key mit passender Länge und Präfix verwenden
}

Sichere Lösung

// Sicher: Vollständiger Passwort-Vergleich
#include <string.h>
#include <openssl/crypto.h>

int sicherer_passwort_check(const char *eingabe, const char *gespeichert) {
    size_t eingabe_länge = strlen(eingabe);
    size_t gespeichert_lange = strlen(gespeichert);

    // Sicher: Vollständige Passwörter vergleichen
    // Konstant-zeitlichen Vergleich verwenden, um Timing-Angriffe zu verhindern
    if (eingabe_länge != gespeichert_lange) {
        // Trotzdem Vergleich durchführen für konstante Zeit
        CRYPTO_memcmp(eingabe, gespeichert, gespeichert_lange);
        return 0;
    }

    // Sicher: Vollständiger Vergleich aller Zeichen
    return CRYPTO_memcmp(eingabe, gespeichert, gespeichert_lange) == 0;
}
// Sicher: Vollständige Token-Validierung einschließlich Signatur
import java.security.*;
import java.util.Base64;

public class SichererTokenValidator {
    private final PublicKey publicKey;

    public SichererTokenValidator(PublicKey publicKey) {
        this.publicKey = publicKey;
    }

    public boolean validateToken(String token) throws Exception {
        String[] parts = token.split("\\.");

        if (parts.length != 3) {
            return false;
        }

        String header = parts[0];
        String payload = parts[1];
        String signature = parts[2];

        // Sicher: Header-Format validieren
        if (!isValidHeader(header)) {
            return false;
        }

        // Sicher: Payload-Claims validieren
        if (!isValidPayload(payload)) {
            return false;
        }

        // Sicher: Signatur verifizieren (vorher fehlend!)
        String signedContent = header + "." + payload;
        byte[] signatureBytes = Base64.getUrlDecoder().decode(signature);

        Signature sig = Signature.getInstance("SHA256withRSA");
        sig.initVerify(publicKey);
        sig.update(signedContent.getBytes("UTF-8"));

        if (!sig.verify(signatureBytes)) {
            return false;  // Signaturverifizierung fehlgeschlagen
        }

        return true;
    }

    private boolean isValidHeader(String header) {
        // Header-Inhalt validieren
        return header != null && header.startsWith("eyJ");
    }

    private boolean isValidPayload(String payload) {
        // Payload-Claims einschließlich Ablauf validieren
        // Implementierungsdetails...
        return true;
    }
}
# Sicher: Vollständige Zertifikatsvalidierung
from cryptography import x509
from cryptography.hazmat.backends import default_backend
from cryptography.x509.oid import ExtensionOID
import datetime

def sichere_zertifikat_validierung(cert, trusted_ca_cert, hostname):
    """Vollständige Zertifikatsvalidierung mit allen Sicherheitsfaktoren"""

    # Sicher: Zertifikatskette prüfen
    try:
        cert.verify_directly_issued_by(trusted_ca_cert)
    except Exception as e:
        return False, f"Kettenverifizierung fehlgeschlagen: {e}"

    # Sicher: Gültigkeitszeitraum prüfen
    jetzt = datetime.datetime.utcnow()
    if jetzt < cert.not_valid_before or jetzt > cert.not_valid_after:
        return False, "Zertifikat nicht innerhalb des Gültigkeitszeitraums"

    # Sicher: Signatur verifizieren
    try:
        trusted_ca_cert.public_key().verify(
            cert.signature,
            cert.tbs_certificate_bytes,
            cert.signature_algorithm_parameters
        )
    except Exception:
        return False, "Signaturverifizierung fehlgeschlagen"

    # Sicher: Schlüsselverwendung prüfen
    try:
        key_usage = cert.extensions.get_extension_for_oid(
            ExtensionOID.KEY_USAGE
        )
        if not key_usage.value.digital_signature:
            return False, "Zertifikat nicht für digitale Signatur gültig"
    except x509.ExtensionNotFound:
        return False, "Fehlende Key-Usage-Erweiterung"

    # Sicher: Subject Alternative Names für Hostname validieren
    try:
        san = cert.extensions.get_extension_for_oid(
            ExtensionOID.SUBJECT_ALTERNATIVE_NAME
        )
        names = san.value.get_values_for_type(x509.DNSName)
        if hostname not in names:
            return False, f"Hostname {hostname} nicht in SAN"
    except x509.ExtensionNotFound:
        # Auf Common Name zurückfallen
        cn = cert.subject.get_attributes_for_oid(x509.oid.NameOID.COMMON_NAME)
        if not cn or cn[0].value != hostname:
            return False, "Hostname-Nichtübereinstimmung"

    return True, "Zertifikat gültig"
// Sicher: Vollständiger API-Schlüssel-Vergleich
const crypto = require('crypto');

function sichereApiKeyValidierung(bereitgestellterKey, gespeicherterKey) {
    // Sicher: Eingabetypen validieren
    if (typeof bereitgestellterKey !== 'string' || typeof gespeicherterKey !== 'string') {
        return false;
    }

    // Sicher: Vollständige Länge prüfen
    if (bereitgestellterKey.length !== gespeicherterKey.length) {
        return false;
    }

    // Sicher: Konstant-zeitlichen Vergleich für GESAMTEN Key verwenden
    // Verhindert Timing-Angriffe und stellt sicher, dass alle Bytes verglichen werden
    return crypto.timingSafeEqual(
        Buffer.from(bereitgestellterKey),
        Buffer.from(gespeicherterKey)
    );
}

// Sicher: Mit zusätzlichen Validierungsfaktoren
function sichereApiKeyValidierungVollständig(request, gespeicherteKeyDaten) {
    const bereitgestellterKey = request.headers['x-api-key'];

    // Sicher: Alle relevanten Faktoren vergleichen

    // Faktor 1: Key-Wert
    if (!crypto.timingSafeEqual(
        Buffer.from(bereitgestellterKey || ''),
        Buffer.from(gespeicherteKeyDaten.key)
    )) {
        return false;
    }

    // Faktor 2: Key nicht abgelaufen
    if (new Date() > new Date(gespeicherteKeyDaten.expiresAt)) {
        return false;
    }

    // Faktor 3: Key nicht widerrufen
    if (gespeicherteKeyDaten.revoked) {
        return false;
    }

    // Faktor 4: Anfrage innerhalb der Rate-Limits
    if (gespeicherteKeyDaten.requestCount > gespeicherteKeyDaten.rateLimit) {
        return false;
    }

    return true;
}

Ausgenutzt in der Praxis

OpenSSL-Zertifikatsvalidierungsfehler (2014)

Ein Fehler in der OpenSSL-Zertifikatsvalidierung (CVE-2014-0092) ermöglichte es, dass bestimmte Zertifikatsfelder bei der Validierung übersprungen wurden, was Man-in-the-Middle-Angriffe ermöglichte.

JWT-Algorithmus-Verwirrung (2015)

Viele JWT-Bibliotheken validierten den Algorithmus-Header nicht vollständig, was es Angreifern ermöglichte, Token mit dem "none"-Algorithmus zu signieren und Authentifizierung zu umgehen.

Passwort-Präfix-Vergleichsfehler

Historisch haben mehrere Systeme nur die ersten Zeichen von Passwörtern verglichen, was die effektive Passwortlänge drastisch reduzierte.


Tools zum Testen und Ausnutzen

  • Burp Suite - Token- und Authentifizierungsprüfung.

  • jwt.io - JWT-Analyse und -Validierung.

  • OpenSSL - Zertifikatsvalidierungstools.


CVE-Beispiele

  • CVE-2005-2177 - Produkt verglich nur erste 8 Zeichen von Passwörtern.

  • CVE-2002-1798 - Produkt validierte nur Zertifikatsaussteller ohne die vollständige Kette zu prüfen.


Referenzen

  1. MITRE Corporation. "CWE-1023: Incomplete Comparison with Missing Factors." https://cwe.mitre.org/data/definitions/1023.html

  2. OWASP. "Authentication Cheat Sheet." https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html

  3. NIST. "Digital Identity Guidelines." https://pages.nist.gov/800-63-3/