Verwendung eines Schlüssels nach seinem Ablaufdatum

Beschreibung

Verwendung eines Schlüssels nach seinem Ablaufdatum ist eine Schwachstelle, die auftritt, wenn ein Produkt kryptografische Schlüssel oder Passwörter über ihr vorgesehenes Ablaufdatum hinaus verwendet. Kryptografische Schlüssel haben Ablaufdaten, um das Zeitfenster zu begrenzen, in dem ein kompromittierter Schlüssel verwendet werden kann, um sicherzustellen, dass Schlüssel mit stärkeren Algorithmen im Laufe der Zeit aktualisiert werden, und um gute Schlüsselverwaltungspraktiken durchzusetzen. Wenn Anwendungen abgelaufene Schlüssel weiter verwenden, verlängern sie das Risikofenster für Brute-Force-Angriffe, verwenden möglicherweise veraltete kryptografische Stärke und untergraben das Schlüssellebenszyklusmanagement, das zur Aufrechterhaltung der Sicherheit entwickelt wurde.

Risiko

Die Verwendung abgelaufener kryptografischer Schlüssel erhöht das Sicherheitsrisiko erheblich durch mehrere Mechanismen. Eine verlängerte Schlüssellebensdauer erhöht das Gesamtvolumen der mit diesem Schlüssel verschlüsselten Daten und bietet mehr Material für Kryptoanalyse. Längere Nutzungsfenster erhöhen die Wahrscheinlichkeit einer Schlüsselkompromittierung durch betriebliche Exposition. Abgelaufene Schlüssel können veraltete Schlüssellängen oder Algorithmen verwenden, die anfällig geworden sind. Organisationen können aufhören, Schlüssel nach dem beabsichtigten Ablauf zu schützen, in der Annahme, dass sie nicht mehr verwendet werden. Das Ablaufdatum von Zertifikaten dient als Kontrollpunkt für das Lebenszyklusmanagement - es zu ignorieren entfernt diese Sicherung. Das Risiko potenziert sich im Laufe der Zeit: Schlüssel, die seit Jahren verwendet werden, akkumulieren Exposition durch Backups, Logs, Personalwechsel und potenzielle Sicherheitsverletzungen. Fortgesetztes Vertrauen in abgelaufene Anmeldedaten signalisiert auch schlechte Sicherheitspraktiken, die sich auf andere Bereiche erstrecken können.

Lösung

Implementieren Sie ordnungsgemäßes Schlüssellebenszyklusmanagement, das Ablaufdaten durchsetzt. Prüfen Sie Schlüssel- und Zertifikats-Ablaufdaten vor der Verwendung und lehnen Sie abgelaufene Anmeldedaten ab. Implementieren Sie automatisierte Schlüsselrotation, die neue Schlüssel vor dem Ablauf generiert und verteilt. Benachrichtigen Sie Benutzer und Administratoren vor dem Schlüsselablauf mit klarer Anleitung zur Erneuerung. Entwerfen Sie Systeme, die Schlüsselübergänge ohne Dienstunterbrechung elegant handhaben. Pflegen Sie Schlüsselinventare, die alle Schlüssel und ihre Ablaufdaten verfolgen. Verwenden Sie Zertifikatsverwaltungssysteme, die Erneuerungsprozesse automatisieren. Für Passwörter implementieren Sie Alterungsrichtlinien, die periodische Änderungen erfordern. Konfigurieren Sie Systeme so, dass Verbindungen mit abgelaufenen Zertifikaten abgelehnt werden. Implementieren Sie Überwachung und Alarmierung für bevorstehende Schlüsselabläufe.

Häufige Auswirkungen

AuswirkungDetails
ZugriffskontrolleUmfang: Zugriffskontrolle

Abgelaufene Schlüssel, die kompromittiert wurden, können weiterhin für Authentifizierung oder Entschlüsselung verwendet werden, was Angreifern ermöglicht, sich als legitime Benutzer auszugeben oder auf geschützte Daten zuzugreifen.
VertraulichkeitUmfang: Vertraulichkeit

Daten, die durch abgelaufene Schlüssel geschützt sind, können einem erhöhten Risiko ausgesetzt sein, wenn die Schlüssel während ihrer erweiterten Nutzung über das beabsichtigte Sicherheitsfenster hinaus kompromittiert wurden.

Beispielcode

Anfälliger Code (C/Java)

Die folgenden Beispiele demonstrieren das Akzeptieren abgelaufener Zertifikate und Schlüssel:

// Anfällig: SSL-Zertifikatsvalidierung ignoriert Ablauf
#include <openssl/ssl.h>
#include <openssl/x509.h>
#include <time.h>

int vulnerable_verify_callback(int preverify_ok, X509_STORE_CTX *ctx) {
    int err = X509_STORE_CTX_get_error(ctx);

    // Noch-nicht-gültig prüfen
    if (err == X509_V_ERR_CERT_NOT_YET_VALID) {
        return 0;  // Ablehnen
    }

    // Anfällig: Keine Prüfung auf Ablauf!
    // X509_V_ERR_CERT_HAS_EXPIRED wird nicht behandelt
    // Abgelaufene Zertifikate werden akzeptiert!

    return preverify_ok;
}

// Anfällig: Manuelle Prüfung ohne Ablaufprüfung
int vulnerable_check_certificate(X509 *cert) {
    // Prüfen ob Zertifikat bereits gültig ist
    if (X509_cmp_time(X509_get_notBefore(cert), NULL) > 0) {
        return 0;  // Noch nicht gültig
    }

    // Anfällig: Fehlende Ablaufprüfung!
    // Sollte prüfen: X509_cmp_time(X509_get_notAfter(cert), NULL) < 0

    return 1;  // Akzeptiert abgelaufene Zertifikate!
}

// Anfällig: API-Schlüssel ohne Ablaufprüfung
typedef struct {
    char key[64];
    time_t created;
    time_t expires;  // Gesetzt aber nie geprüft!
} ApiKey;

int vulnerable_validate_api_key(ApiKey *key) {
    // Anfällig: Prüft nur ob Schlüssel existiert
    if (strlen(key->key) > 0) {
        return 1;  // Gültig - aber könnte abgelaufen sein!
    }
    return 0;
}
// Anfällig: Java-Zertifikatsvalidierung ignoriert Ablauf
import java.security.cert.*;
import javax.net.ssl.*;

public class VulnerableCertValidator {

    // Anfällig: Benutzerdefinierter TrustManager ignoriert Ablauf
    public static TrustManager[] getVulnerableTrustManagers() {
        return new TrustManager[] {
            new X509TrustManager() {
                public void checkClientTrusted(X509Certificate[] chain, String auth) {
                    // Anfällig: Keine Ablaufprüfung!
                }

                public void checkServerTrusted(X509Certificate[] chain, String auth)
                        throws CertificateException {
                    for (X509Certificate cert : chain) {
                        // Anfällig: Prüft nur ob noch nicht gültig
                        try {
                            cert.checkValidity();
                        } catch (CertificateNotYetValidException e) {
                            throw e;  // Noch-nicht-gültig ablehnen
                        } catch (CertificateExpiredException e) {
                            // Anfällig: Ablauf ignorieren!
                            System.out.println("Warnung: Zertifikat abgelaufen (ignoriert)");
                        }
                    }
                }

                public X509Certificate[] getAcceptedIssuers() {
                    return new X509Certificate[0];
                }
            }
        };
    }

    // Anfällig: Lizenzschlüssel ohne Ablaufdurchsetzung
    public boolean validateLicense(LicenseKey license) {
        // Anfällig: Validiert nur Signatur, nicht Ablauf
        return license.verifySignature();
        // license.getExpirationDate() wird nie geprüft!
    }
}
# Anfällig: Python-Zertifikatshandhabung ignoriert Ablauf
import ssl
from datetime import datetime
from cryptography import x509

def vulnerable_validate_certificate(cert_pem):
    cert = x509.load_pem_x509_certificate(cert_pem.encode())

    # Prüfen ob Zertifikat bereits gültig ist
    if cert.not_valid_before > datetime.utcnow():
        return False  # Noch nicht gültig

    # Anfällig: Keine Ablaufprüfung!
    # Sollte prüfen: cert.not_valid_after < datetime.utcnow()

    return True  # Akzeptiert abgelaufene Zertifikate!

# Anfällig: JWT-Token ohne Ablaufprüfung
import jwt

def vulnerable_validate_token(token, secret):
    try:
        # Anfällig: Ablauf nicht verifizieren
        payload = jwt.decode(
            token,
            secret,
            algorithms=['HS256'],
            options={'verify_exp': False}  # Ablaufprüfung deaktiviert!
        )
        return payload
    except jwt.InvalidTokenError:
        return None

Korrigierter Code (C/Java)

// Korrigiert: Ordnungsgemäße Zertifikats-Ablaufvalidierung
#include <openssl/ssl.h>
#include <openssl/x509.h>
#include <time.h>

int strict_verify_callback(int preverify_ok, X509_STORE_CTX *ctx) {
    if (!preverify_ok) {
        int err = X509_STORE_CTX_get_error(ctx);

        // Korrigiert: Ablaufsfehler explizit behandeln
        if (err == X509_V_ERR_CERT_HAS_EXPIRED) {
            X509 *cert = X509_STORE_CTX_get_current_cert(ctx);
            char subject[256];
            X509_NAME_oneline(X509_get_subject_name(cert), subject, sizeof(subject));
            fprintf(stderr, "Zertifikat abgelaufen: %s\n", subject);
            return 0;  // Abgelaufene Zertifikate ablehnen
        }

        if (err == X509_V_ERR_CERT_NOT_YET_VALID) {
            return 0;  // Noch-nicht-gültig ablehnen
        }

        return 0;  // Alle anderen Fehler ablehnen
    }

    return 1;
}

// Korrigiert: Vollständige Zertifikatsgültigkeitsprüfung
int secure_check_certificate(X509 *cert) {
    time_t now = time(NULL);

    // Korrigiert: Noch-nicht-gültig prüfen
    if (X509_cmp_time(X509_get0_notBefore(cert), &now) > 0) {
        fprintf(stderr, "Zertifikat noch nicht gültig\n");
        return 0;
    }

    // Korrigiert: Ablauf prüfen
    if (X509_cmp_time(X509_get0_notAfter(cert), &now) < 0) {
        fprintf(stderr, "Zertifikat ist abgelaufen\n");
        return 0;
    }

    // Korrigiert: Warnung für bald ablaufende Zertifikate
    time_t warning_threshold = now + (30 * 24 * 60 * 60);  // 30 Tage
    if (X509_cmp_time(X509_get0_notAfter(cert), &warning_threshold) < 0) {
        fprintf(stderr, "Warnung: Zertifikat läuft innerhalb von 30 Tagen ab\n");
    }

    return 1;
}

// Korrigiert: API-Schlüssel mit Ablaufdurchsetzung
typedef struct {
    char key[64];
    time_t created;
    time_t expires;
} ApiKey;

int secure_validate_api_key(ApiKey *key) {
    if (strlen(key->key) == 0) {
        return 0;  // Leerer Schlüssel
    }

    // Korrigiert: Ablauf prüfen
    time_t now = time(NULL);
    if (now > key->expires) {
        fprintf(stderr, "API-Schlüssel ist abgelaufen\n");
        return 0;  // Abgelaufene Schlüssel ablehnen
    }

    // Korrigiert: Warnung für bald ablaufende Schlüssel
    if (now > key->expires - (7 * 24 * 60 * 60)) {  // 7 Tage
        fprintf(stderr, "Warnung: API-Schlüssel läuft bald ab\n");
    }

    return 1;
}
// Korrigiert: Java-Zertifikatsvalidierung mit ordnungsgemäßer Ablaufprüfung
import java.security.cert.*;
import javax.net.ssl.*;
import java.util.Date;

public class SecureCertValidator {

    // Korrigiert: TrustManager der Ablauf ordnungsgemäß prüft
    public static SSLContext getSecureSSLContext() throws Exception {
        // Standard-Trust-Manager verwenden der Ablauf prüft
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(
            TrustManagerFactory.getDefaultAlgorithm());
        tmf.init((KeyStore) null);

        SSLContext sslContext = SSLContext.getInstance("TLSv1.3");
        sslContext.init(null, tmf.getTrustManagers(), null);

        return sslContext;
    }

    // Korrigiert: Explizite Ablaufprüfung für zusätzliche Validierung
    public static void validateCertificateExpiration(X509Certificate cert)
            throws CertificateException {

        Date now = new Date();

        // Korrigiert: Prüfen ob Zertifikat gültig ist (beinhaltet Ablauf)
        try {
            cert.checkValidity(now);
        } catch (CertificateExpiredException e) {
            throw new CertificateException("Zertifikat ist abgelaufen", e);
        } catch (CertificateNotYetValidException e) {
            throw new CertificateException("Zertifikat noch nicht gültig", e);
        }

        // Korrigiert: Warnen wenn bald ablaufend
        Date warningDate = new Date(System.currentTimeMillis() +
                                    30L * 24 * 60 * 60 * 1000);  // 30 Tage
        if (cert.getNotAfter().before(warningDate)) {
            System.err.println("Warnung: Zertifikat läuft ab am " +
                              cert.getNotAfter());
        }
    }

    // Korrigiert: Lizenzvalidierung mit Ablauf
    public boolean validateLicense(LicenseKey license) {
        // Korrigiert: Signatur prüfen
        if (!license.verifySignature()) {
            return false;
        }

        // Korrigiert: Ablauf prüfen
        Date now = new Date();
        if (license.getExpirationDate().before(now)) {
            System.err.println("Lizenz ist abgelaufen");
            return false;
        }

        return true;
    }
}
# Korrigiert: Ordnungsgemäße Ablaufvalidierung
from datetime import datetime, timedelta
from cryptography import x509
import jwt

def secure_validate_certificate(cert_pem):
    cert = x509.load_pem_x509_certificate(cert_pem.encode())
    now = datetime.utcnow()

    # Korrigiert: Noch-nicht-gültig prüfen
    if cert.not_valid_before > now:
        raise ValueError("Zertifikat noch nicht gültig")

    # Korrigiert: Ablauf prüfen
    if cert.not_valid_after < now:
        raise ValueError("Zertifikat ist abgelaufen")

    # Korrigiert: Warnung für bald ablaufende Zertifikate
    warning_threshold = now + timedelta(days=30)
    if cert.not_valid_after < warning_threshold:
        print(f"Warnung: Zertifikat läuft ab am {cert.not_valid_after}")

    return True

# Korrigiert: JWT mit Ablaufverifizierung
def secure_validate_token(token, secret):
    try:
        # Korrigiert: Ablauf verifizieren (Standardverhalten)
        payload = jwt.decode(
            token,
            secret,
            algorithms=['HS256'],
            options={
                'verify_exp': True,  # Ablauf verifizieren (Standard)
                'require': ['exp', 'iat']  # Diese Claims erfordern
            }
        )
        return payload
    except jwt.ExpiredSignatureError:
        raise ValueError("Token ist abgelaufen")
    except jwt.InvalidTokenError as e:
        raise ValueError(f"Ungültiges Token: {e}")

# Korrigiert: API-Schlüssel-Validierung mit Ablauf
class SecureApiKeyValidator:
    def validate(self, api_key):
        key_record = self.get_key_record(api_key)

        if not key_record:
            return False

        # Korrigiert: Ablauf prüfen
        now = datetime.utcnow()
        if key_record.expires_at < now:
            self.log_expired_key_use(api_key)
            return False

        # Korrigiert: Über bald ablaufende Schlüssel warnen
        if key_record.expires_at < now + timedelta(days=7):
            self.notify_key_expiration(api_key, key_record.expires_at)

        return True

Die Korrektur validiert ordnungsgemäß Ablaufdaten und lehnt abgelaufene Anmeldedaten ab.


Ausgenutzt in der Praxis

Krankenhaus-PACS-System (Gesundheitswesen, 2021)

CVE-2021-33020 dokumentierte ein Krankenhaus-PACS (Picture Archiving and Communication System), das kryptografische Schlüssel über ihr Ablaufdatum hinaus verwendete und die Sicherheit von Patientendaten kompromittierte.

Akzeptanz abgelaufener Zertifikate (Verschiedene, laufend)

Mehrere Anwendungen wurden gefunden, die abgelaufene SSL/TLS-Zertifikate akzeptierten, was Man-in-the-Middle-Angriffe ermöglichte.


Tools zum Testen/Ausnutzen

  • testssl.sh — Kommandozeilen-Tool zum Testen von SSL/TLS einschließlich Zertifikatsablauf.

  • OpenSSL — Tools zur Untersuchung von Zertifikatsgültigkeitszeiträumen.

  • Certificate Monitoring Services — Online-Tools zur Prüfung des Zertifikatsstatus.


CVE-Beispiele

  • CVE-2021-33020 — Krankenhaussystem verwendet Schlüssel nach Ablauf.

Referenzen

  1. MITRE Corporation. "CWE-324: Use of a Key Past its Expiration Date." Common Weakness Enumeration. https://cwe.mitre.org/data/definitions/324.html

  2. NIST. "Recommendation for Key Management." SP 800-57. https://csrc.nist.gov/publications/detail/sp/800-57-part-1/rev-5/final

  3. OWASP Foundation. "Key Management Cheat Sheet." https://cheatsheetseries.owasp.org/cheatsheets/Key_Management_Cheat_Sheet.html