Kritisches Datenelement als Public deklariert

Beschreibung

Kritisches Datenelement als Public deklariert ist eine Kapselungsschwachstelle, bei der Software eine kritische Variable, ein Feld oder ein Member als public deklariert, obwohl die beabsichtigte Sicherheitsrichtlinie erfordert, dass es privat ist. Dies tritt typischerweise in objektorientierten Sprachen auf, in denen Zugriffsmodifikatoren die Sichtbarkeit von Klassenmembern steuern. Wenn sicherheitsrelevante Daten wie Passwörter, kryptografische Schlüssel oder interne Zustandsvariablen als public deklariert werden, kann jeder Code mit Zugriff auf das Objekt diese Werte lesen oder ändern und dabei beabsichtigte Zugriffskontrollen und Sicherheitsgrenzen umgehen.

Risiko

Die Deklaration kritischer Datenelemente als public erzeugt erhebliche Sicherheits- und Wartbarkeitsrisiken. Angreifer oder bösartiger Code mit Zugriff auf das Objekt können direkt sensible Informationen lesen (Passwörter, Token, Schlüssel) oder kritische Zustandsvariablen ändern, um Sicherheitsprüfungen zu umgehen. Dies verletzt das Prinzip des Information Hiding und bricht die Kapselung, was es schwierig macht, Sicherheitsinvarianten durchzusetzen. Das Problem wirkt sich auch auf die Wartbarkeit aus, da es eine enge Kopplung zwischen Komponenten erzeugt und Sicherheitskorrekturen erschwert.

Lösung

Deklarieren Sie sicherheitskritische Variablen immer als private (oder protected, wenn Vererbung dies erfordert). Verwenden Sie Accessor (Getter) und Mutator (Setter) Methoden, die Validierung und Zugriffskontrolle durchsetzen können. Markieren Sie Felder als final/const, wenn sich der Wert nach der Initialisierung nicht ändern soll. Wenden Sie das Prinzip der geringsten Privilegien auf den Datenzugriff an - exponieren Sie nur das absolut Notwendige durch kontrollierte Schnittstellen. Verwenden Sie automatisierte statische Analysetools, um public-Deklarationen sensibler Datentypen zu erkennen.

Häufige Auswirkungen

AuswirkungDetails
VertraulichkeitBereich: Vertraulichkeit

Anwendungsdaten lesen - Public-Deklaration erlaubt jedem Code mit Objektzugriff, sensible Werte direkt zu lesen.
IntegritätBereich: Integrität

Anwendungsdaten ändern - Public-Deklaration erlaubt jedem Code, kritische Werte zu ändern und möglicherweise Sicherheitsprüfungen zu umgehen.
SonstigesBereich: Sonstiges

Wartbarkeit reduziert - Erschwert Änderungen der internen Implementierung ohne Auswirkungen auf abhängigen Code.

Beispielcode

Verwundbarer Code

// Verwundbar: Passwort als public deklariert
class UserAccount {
public:
    char* username;
    char* password;      // Verwundbar: Sollte private sein
    int accountBalance;  // Verwundbar: Sollte private sein
    bool isAdmin;        // Verwundbar: Kritisches Sicherheitsflag public

    void authenticate(const char* inputPassword) {
        if (strcmp(password, inputPassword) == 0) {
            // Authentifiziert
        }
    }
};

void exploit() {
    UserAccount user;
    // Angreifer kann direkt auf sensible Daten zugreifen
    printf("Password: %s\n", user.password);  // Direkter Lesezugriff
    user.isAdmin = true;  // Privilegieneskalation
    user.accountBalance = 999999;  // Datenmanipulation
}
// Verwundbar: Java-Klasse mit public sensiblen Feldern
public class BankAccount {
    public String accountNumber;
    public double balance;      // Verwundbar: Sollte private sein
    public String pin;          // Verwundbar: Kritische Anmeldedaten public
    public String[] transactionHistory;  // Verwundbar: Sensible Daten

    public BankAccount(String accountNumber, String pin) {
        this.accountNumber = accountNumber;
        this.pin = pin;
        this.balance = 0;
    }
}

// Ausnutzung
class AttackerCode {
    public void steal(BankAccount victim) {
        System.out.println("PIN: " + victim.pin);  // Direkter Zugriff
        victim.balance = 0;  // Direkte Manipulation
    }
}

Gefixter Code

// Gefixt: Korrekte Kapselung mit privaten Membern
class UserAccount {
private:
    std::string username;
    std::string password;      // Private: Vor direktem Zugriff geschützt
    int accountBalance;        // Private: Kontrollierter Zugriff
    bool isAdmin;              // Private: Sicherheitsflag geschützt

public:
    UserAccount(const std::string& user, const std::string& pass)
        : username(user), password(pass), accountBalance(0), isAdmin(false) {}

    // Kontrollierte Accessoren mit Validierung
    std::string getUsername() const { return username; }

    bool authenticate(const std::string& inputPassword) const {
        return password == inputPassword;
    }

    int getBalance() const { return accountBalance; }

    bool deposit(int amount) {
        if (amount > 0) {
            accountBalance += amount;
            return true;
        }
        return false;
    }

    // Kein public Setter für isAdmin - nur durch System kontrolliert
    bool checkAdmin() const { return isAdmin; }
};
// Gefixt: Korrekte Kapselung in Java
public class BankAccount {
    private final String accountNumber;  // Unveränderlicher Identifier
    private double balance;
    private String pin;
    private final List<String> transactionHistory;

    public BankAccount(String accountNumber, String pin) {
        this.accountNumber = accountNumber;
        this.pin = pin;
        this.balance = 0;
        this.transactionHistory = new ArrayList<>();
    }

    public String getAccountNumber() {
        return accountNumber;
    }

    public double getBalance() {
        return balance;
    }

    // Kein Getter für PIN - nur Validierungsmethode
    public boolean validatePin(String inputPin) {
        return MessageDigest.isEqual(
            pin.getBytes(StandardCharsets.UTF_8),
            inputPin.getBytes(StandardCharsets.UTF_8)
        );
    }

    public synchronized void deposit(double amount) {
        if (amount > 0) {
            balance += amount;
            transactionHistory.add("Einzahlung: " + amount);
        }
    }

    // Defensive Kopie der Transaktionshistorie zurückgeben
    public List<String> getTransactionHistory() {
        return new ArrayList<>(transactionHistory);
    }
}

CVE-Beispiele

  • CVE-2010-3860: JBoss MicroContainer erlaubte entfernten Angreifern das Lesen von Systemeigenschaften wie Benutzername und Home-Verzeichnis über als public deklarierte Variablen in Klassendefinitionen.

Referenzen

  1. MITRE Corporation. "CWE-766: Critical Data Element Declared Public." https://cwe.mitre.org/data/definitions/766.html
  2. CERT C++ Coding Standard. "OOP03-CPP. Use accessor and mutator methods for data encapsulation."
  3. Oracle Java Secure Coding Guidelines. "SECCODE-4: Restrict privileges and expose minimal data."