Fehlende Prüfung auf Zertifikatswiderruf nach initialer Prüfung

Beschreibung

Fehlende Prüfung auf Zertifikatswiderruf nach initialer Prüfung ist eine Schwachstelle, die auftritt, wenn ein Produkt den Zertifikatswiderrufsstatus nicht vor jeder privilegierten Aktion verifiziert und nur bei der initialen Verbindung oder Authentifizierung prüft. Ein Zertifikat kann zwischen der initialen Prüfung und nachfolgenden Operationen widerrufen werden aufgrund von Schlüsselkompromittierung, Richtlinienänderungen oder Mitarbeiterbeendigung. Dies schafft ein Zeitfenster, in dem widerrufene Anmeldedaten ihre Privilegien behalten, was fortgesetzten Zugang ermöglicht, der hätte beendet werden sollen. Die Schwachstelle ist im Wesentlichen eine TOCTOU (Time-of-Check Time-of-Use) Race Condition angewendet auf Zertifikatsvalidierung.

Risiko

Diese Schwachstelle ermöglicht Angreifern mit widerrufenen Zertifikaten, weiterhin auf geschützte Ressourcen zuzugreifen, bis die Sitzung endet oder eine periodische Neuprüfung stattfindet. Wenn ein privater Schlüssel kompromittiert und das Zertifikat widerrufen wird, können Angreifer den kompromittierten Schlüssel immer noch für den Rest aktiver Sitzungen verwenden. Bei langlebigen Verbindungen oder Sitzungen mit seltener Neuauthentifizierung kann das Zeitfenster der Exposition erheblich sein. Gekündigte Mitarbeiter, deren Zertifikate widerrufen werden, behalten möglicherweise Zugang. Das Risiko ist besonders schwerwiegend für hochsichere Anwendungen, bei denen sofortiger Widerruf kritisch ist, wie Finanzsysteme, Gesundheitsanwendungen oder Zugangskon trollsysteme.

Lösung

Stellen Sie sicher, dass Zertifikate vor jeder Nutzung einer geschützten Ressource auf Widerrufsstatus geprüft werden, nicht nur bei der initialen Authentifizierung. Implementieren Sie kurze Sitzungs-Timeouts, die Neuauthentifizierung erfordern. Verwenden Sie OCSP-Stapling, um den Widerrufsstatus effizient zu prüfen. Cachen Sie den Widerrufsstatus für kurze Zeiträume (Minuten, nicht Stunden), um Leistung und Sicherheit auszubalancieren. Erwägen Sie die Verwendung von Certificate-Transparency-Logs für zusätzliche Verifizierung. Implementieren Sie Echtzeit-Widerrufsprüfung für hochsichere Operationen. Entwerfen Sie Systeme, um die Zeit zwischen Widerruf und Durchsetzung zu minimieren.

Häufige Auswirkungen

AuswirkungDetails
ZugriffskontrolleUmfang: Zugriffskontrolle

Vertrauen kann einer Entität zugewiesen werden, die nicht die ist, die sie vorgibt zu sein, da widerrufene Anmeldedaten weiter funktionieren.
IntegritätUmfang: Integrität

Daten aus einer nicht vertrauenswürdigen Quelle können integriert werden, wenn widerrufene Zertifikate noch akzeptiert werden.
VertraulichkeitUmfang: Vertraulichkeit

Daten können einer Entität offengelegt werden, die sich mit widerrufenen Anmeldedaten als vertrauenswürdige Entität ausgibt.

Beispielcode

Anfälliger Code

// Anfällig: Prüft Zertifikat nur bei Verbindungszeit
public class VulnerableSSLServer {

    public void handleConnection(SSLSocket socket) throws Exception {
        // Zertifikat nur beim Handshake geprüft
        SSLSession session = socket.getSession();
        X509Certificate[] certs = (X509Certificate[])
            session.getPeerCertificates();

        // Initiale Verifizierung
        verifyCertificate(certs[0]);

        // Anfällig: Keine Widerrufsprüfung für nachfolgende Operationen
        while (true) {
            String command = readCommand(socket);
            // Zertifikat könnte seit Verbindung widerrufen worden sein
            executePrivilegedCommand(command);  // Gefährlich!
        }
    }

    private void verifyCertificate(X509Certificate cert) {
        // Prüft nur Gültigkeit, nicht Widerruf für jede Operation
    }
}
# Anfällig: Sitzung verwendet initiale Zertifikatsvalidierung wieder
class VulnerableAuthenticator:
    def __init__(self):
        self.authenticated_sessions = {}

    def authenticate(self, cert, session_id):
        # Anfällig: Prüft Widerruf nur beim Login
        if self.verify_certificate(cert) and not self.is_revoked(cert):
            self.authenticated_sessions[session_id] = {
                'cert': cert,
                'authenticated_at': time.time()
            }
            return True
        return False

    def perform_action(self, session_id, action):
        # Anfällig: Keine erneute Widerrufsprüfung
        if session_id in self.authenticated_sessions:
            # Zertifikat könnte jetzt widerrufen sein!
            execute_action(action)

Korrigierter Code

// Korrigiert: Widerruf vor jeder privilegierten Operation prüfen
public class SecureSSLServer {

    private OCSPChecker ocspChecker;
    private int maxOperationsBeforeRecheck = 10;
    private int operationCount = 0;

    public void handleConnection(SSLSocket socket) throws Exception {
        SSLSession session = socket.getSession();
        X509Certificate[] certs = (X509Certificate[])
            session.getPeerCertificates();
        X509Certificate clientCert = certs[0];

        // Initiale Verifizierung
        verifyAndCheckRevocation(clientCert);

        while (true) {
            String command = readCommand(socket);

            // Korrigiert: Widerruf periodisch erneut prüfen
            operationCount++;
            if (operationCount >= maxOperationsBeforeRecheck) {
                verifyAndCheckRevocation(clientCert);
                operationCount = 0;
            }

            executePrivilegedCommand(command);
        }
    }

    private void verifyAndCheckRevocation(X509Certificate cert) throws Exception {
        // Zertifikatskette verifizieren
        verifyCertificateChain(cert);

        // Korrigiert: OCSP/CRL auf Widerruf prüfen
        if (ocspChecker.isRevoked(cert)) {
            throw new CertificateRevokedException("Zertifikat wurde widerrufen");
        }
    }
}

// Korrigiert: Widerruf vor jeder sensiblen Operation prüfen
public class SecureOperationHandler {

    public void performSensitiveOperation(X509Certificate cert, Operation op)
            throws Exception {
        // Korrigiert: Widerruf vor JEDER sensiblen Operation prüfen
        checkRevocationStatus(cert);

        // Nur fortfahren wenn Zertifikat noch gültig ist
        executeOperation(op);
    }

    private void checkRevocationStatus(X509Certificate cert) throws Exception {
        // OCSP für Echtzeit-Widerrufsprüfung verwenden
        OCSPResponse response = queryOCSP(cert);

        if (response.getStatus() == OCSPResponseStatus.REVOKED) {
            throw new CertificateRevokedException("Zertifikat widerrufen");
        }
    }
}
# Korrigiert: Zertifikatsstatus regelmäßig erneut prüfen
import time
from functools import wraps

class SecureAuthenticator:
    RECHECK_INTERVAL = 300  # 5 Minuten

    def __init__(self):
        self.authenticated_sessions = {}

    def authenticate(self, cert, session_id):
        if self.verify_certificate(cert) and not self.is_revoked(cert):
            self.authenticated_sessions[session_id] = {
                'cert': cert,
                'authenticated_at': time.time(),
                'last_revocation_check': time.time()
            }
            return True
        return False

    def _check_session_validity(self, session_id):
        """Korrigiert: Widerrufsstatus periodisch erneut prüfen."""
        session = self.authenticated_sessions.get(session_id)
        if not session:
            return False

        cert = session['cert']
        last_check = session['last_revocation_check']

        # Korrigiert: Erneut prüfen wenn Intervall überschritten
        if time.time() - last_check > self.RECHECK_INTERVAL:
            if self.is_revoked(cert):
                del self.authenticated_sessions[session_id]
                return False
            session['last_revocation_check'] = time.time()

        return True

    def perform_action(self, session_id, action):
        # Korrigiert: Sitzung vor jeder Aktion validieren
        if not self._check_session_validity(session_id):
            raise PermissionError("Sitzung ungültig oder Zertifikat widerrufen")

        execute_action(action)

    # Korrigiert: Decorator für sensible Operationen
    def require_valid_cert(self, func):
        @wraps(func)
        def wrapper(session_id, *args, **kwargs):
            session = self.authenticated_sessions.get(session_id)
            if not session:
                raise PermissionError("Nicht authentifiziert")

            # Korrigiert: Widerruf für sensible Ops immer prüfen
            if self.is_revoked(session['cert']):
                del self.authenticated_sessions[session_id]
                raise PermissionError("Zertifikat widerrufen")

            return func(session_id, *args, **kwargs)
        return wrapper

CVE-Beispiele

Keine spezifischen CVEs sind für diese CWE gelistet, aber das Schwachstellenmuster erscheint in:

  • Langlebigen TLS-Sitzungen ohne Widerrufs-Neuprüfung
  • Webanwendungen, die Client-Zertifikate verwenden
  • VPN-Systemen mit Zertifikatsauthentifizierung

Referenzen

  1. MITRE Corporation. "CWE-370: Missing Check for Certificate Revocation after Initial Check." https://cwe.mitre.org/data/definitions/370.html
  2. RFC 6960. "Online Certificate Status Protocol - OCSP." https://tools.ietf.org/html/rfc6960