Die UI führt die falsche Aktion aus

Beschreibung

Die UI führt die falsche Aktion aus ist eine Schwachstelle, bei der die Benutzeroberfläche eine inkorrekte Operation ausführt, obwohl sie ordnungsgemäße Benutzereingaben erhalten hat. Wenn ein Benutzer eine Aktion über die UI initiiert, führt das System eine andere Aktion als beabsichtigt aus, was potenziell zu Sicherheitsverletzungen, Datenverlust oder Systemfehlkonfiguration führt. Dies kann durch Implementierungsfehler, inkorrekte Zuordnungen zwischen UI-Elementen und Backend-Funktionen oder Logikfehler im Aktions-Dispatch auftreten.

Risiko

Wenn UI falsche Aktionen ausführt, verlieren Benutzer die Kontrolle über das Systemverhalten. Sicherheitseinstellungen können fehlkonfiguriert werden, wenn Benutzer glauben, Einschränkungen anzuwenden. Sensible Daten können exponiert werden, wenn Benutzer versuchen, sie zu schützen. Zugriffsberechtigungen können gewährt werden, wenn Benutzer beabsichtigen, sie zu widerrufen. Das Risiko wird verstärkt, weil Benutzer darauf vertrauen, dass das System die von ihnen angeforderte Aktion ausführt, und das tatsächliche Ergebnis möglicherweise nicht verifizieren. Angreifer können vorhersagbare Falschaktion-Muster ausnutzen, um Systeme durch legitime Benutzerinteraktionen zu manipulieren.

Lösung

Implementieren Sie umfassende Tests, die verifizieren, dass UI-Aktionen korrekte Backend-Ergebnisse produzieren. Verwenden Sie automatisierte UI-Test-Frameworks, die Aktionsergebnisse validieren, nicht nur UI-Zustandsänderungen. Ordnen Sie UI-Elemente Backend-Funktionen durch einen zentralisierten, auditierbaren Dispatch-Mechanismus zu. Implementieren Sie Aktionsbestätigung für kritische Operationen, die genau zeigt, was ausgeführt wird. Protokollieren Sie alle Aktionen mit sowohl beabsichtigten als auch tatsächlichen Operationen für Audit-Zwecke. Verwenden Sie Vertragstests zwischen UI und Backend, um sicherzustellen, dass Aktionssemantiken über Updates hinweg konsistent bleiben.

Häufige Auswirkungen

AuswirkungDetails
SonstigesUmfang: Sonstiges

Qualitätsverschlechterung - Systemqualität verschlechtert sich, wenn Benutzeraktionen unerwartete Ergebnisse produzieren, was zu Benutzerfrust und potenziellen Sicherheitsproblemen führt.
SonstigesUmfang: Sonstiges

Variiert je nach Kontext - Sicherheitsauswirkung hängt von der spezifischen falschen Aktion ab. Kann Datenexposition, Zugriffskontrollumgehung oder Konfigurationsfehler verursachen.

Beispielcode

Anfälliger Code

// Anfällig: Button-Click-Handler falsch zugeordnet
class VulnerableUserManagement {

    constructor() {
        // Anfällig: Aktions-Handler vertauscht
        this.actions = {
            'grant_access': this.revokeUserAccess.bind(this),  // FALSCH!
            'revoke_access': this.grantUserAccess.bind(this),  // FALSCH!
            'delete_user': this.suspendUser.bind(this),        // Falsche Aktion
            'suspend_user': this.deleteUser.bind(this)         // Falsche Aktion
        };
    }

    handleButtonClick(action, userId) {
        // Benutzer klickt "Zugriff widerrufen" aber gewährt stattdessen Zugriff
        if (this.actions[action]) {
            return this.actions[action](userId);
        }
    }

    grantUserAccess(userId) {
        setUserPermission(userId, 'full_access');
        return { message: 'Benutzerzugriff gewährt' };  // Korrekte Meldung, falsche Aktion
    }

    revokeUserAccess(userId) {
        setUserPermission(userId, 'no_access');
        return { message: 'Benutzerzugriff widerrufen' };  // Korrekte Meldung, falsche Aktion
    }
}
# Anfällig: Formularübermittlung führt falsche Datenbankoperation aus
class VulnerableDataForm:
    def handle_submit(self, form_data, operation):
        # Anfällig: Operations-Parameter entspricht nicht der tatsächlichen Operation
        if operation == 'encrypt':
            # Bug: Entschlüsselt tatsächlich statt zu verschlüsseln
            return self.decrypt_data(form_data)  # FALSCHE AKTION!

        elif operation == 'decrypt':
            # Bug: Verschlüsselt tatsächlich statt zu entschlüsseln
            return self.encrypt_data(form_data)  # FALSCHE AKTION!

        elif operation == 'delete_selected':
            # Bug: Löscht ALLES statt Ausgewähltem
            return self.delete_all()  # FALSCHE AKTION!

    def process_file_operation(self, filename, action):
        # Anfällig: Copy/Paste-Fehler in Bedingungen
        if action == 'make_public':
            self.set_private(filename)  # FALSCH - sollte set_public sein

        elif action == 'make_private':
            self.set_public(filename)   # FALSCH - sollte set_private sein

        return f"Datei {filename}: {action} abgeschlossen"  # Irreführende Meldung
// Anfällig: Firewall-Regeln mit falscher Richtung angewendet
public class VulnerableFirewallUI {

    public void applyRule(FirewallRule rule) {
        // Anfällig: UI sagt "Eingehend blockieren" aber blockiert ausgehend
        if (rule.getDirection() == Direction.INBOUND) {
            // Bug: Falsche Methode aufgerufen
            blockOutbound(rule.getPort());  // Sollte blockInbound sein!
        } else if (rule.getDirection() == Direction.OUTBOUND) {
            // Bug: Falsche Methode aufgerufen
            blockInbound(rule.getPort());   // Sollte blockOutbound sein!
        }

        // Benutzeroberfläche zeigt "Eingehenden Verkehr auf Port 443 blockiert"
        // Tatsächlich ausgehend blockiert - Benutzer können keine HTTPS-Seiten erreichen
        logRuleApplication(rule);
    }

    // Anfällig: Toggle führt gegenteilige Aktion aus
    public void toggleFeature(String feature, boolean enable) {
        switch (feature) {
            case "intrusion_detection":
                if (enable) {
                    disableIDS();  // FALSCH - sollte aktivieren
                } else {
                    enableIDS();   // FALSCH - sollte deaktivieren
                }
                break;

            case "logging":
                // Bug: Timeout-Funktionalität invertiert
                if (enable) {
                    setLogTimeout(0);     // Deaktiviert Logging!
                } else {
                    setLogTimeout(3600);  // Aktiviert Logging!
                }
                break;
        }
    }
}
// Anfällig: Kommandozeilen-Tool mit falscher Options-Implementierung
#include <stdio.h>
#include <string.h>

// Anfällig: Optionen machen das Gegenteil der Dokumentation
void process_options(int argc, char *argv[]) {
    for (int i = 1; i < argc; i++) {
        if (strcmp(argv[i], "--enable-encryption") == 0) {
            // Bug: Deaktiviert statt zu aktivieren
            disable_encryption();  // FALSCHE AKTION
            printf("Verschlüsselung aktiviert\n");  // Irreführende Ausgabe

        } else if (strcmp(argv[i], "--disable-logging") == 0) {
            // Bug: Aktiviert statt zu deaktivieren
            enable_detailed_logging();  // FALSCHE AKTION
            printf("Logging deaktiviert\n");  // Benutzer denkt Logging ist aus
            // Tatsächlich detailliertes Logging aktiviert - Datenschutzproblem
        }
    }
}

// Anfällig: Berechtigungs-Bits falsch gesetzt
void set_file_permissions(const char *filename, const char *mode) {
    if (strcmp(mode, "private") == 0) {
        // Bug: Setzt weltlesbar statt privat
        chmod(filename, 0644);  // FALSCH - sollte 0600 sein
        printf("Datei auf privat gesetzt\n");

    } else if (strcmp(mode, "public") == 0) {
        // Bug: Setzt privat statt öffentlich
        chmod(filename, 0600);  // FALSCH - sollte 0644 sein
        printf("Datei auf öffentlich gesetzt\n");
    }
}

Korrigierter Code

// Korrigiert: Aktions-Handler mit Verifizierung
class SecureUserManagement {

    constructor() {
        // Korrigiert: Klare, verifizierte Aktionszuordnungen
        this.actions = new Map([
            ['grant_access', {
                handler: this.grantUserAccess.bind(this),
                verify: this.verifyAccessGranted.bind(this),
                description: 'Benutzerzugriff gewähren'
            }],
            ['revoke_access', {
                handler: this.revokeUserAccess.bind(this),
                verify: this.verifyAccessRevoked.bind(this),
                description: 'Benutzerzugriff widerrufen'
            }],
            ['delete_user', {
                handler: this.deleteUser.bind(this),
                verify: this.verifyUserDeleted.bind(this),
                description: 'Benutzer dauerhaft löschen'
            }],
            ['suspend_user', {
                handler: this.suspendUser.bind(this),
                verify: this.verifyUserSuspended.bind(this),
                description: 'Benutzerkonto sperren'
            }]
        ]);
    }

    async handleButtonClick(action, userId) {
        const actionConfig = this.actions.get(action);

        if (!actionConfig) {
            return { success: false, error: 'Unbekannte Aktion' };
        }

        // Korrigiert: Beabsichtigte Aktion protokollieren
        auditLog.record('ACTION_INITIATED', {
            action,
            userId,
            description: actionConfig.description,
            timestamp: Date.now()
        });

        // Korrigiert: Aktion ausführen
        const result = await actionConfig.handler(userId);

        // Korrigiert: Verifizieren, dass korrekte Aktion ausgeführt wurde
        const verified = await actionConfig.verify(userId);

        if (!verified) {
            // Korrigiert: Bei Verifizierungsfehler alarmieren
            auditLog.record('ACTION_VERIFICATION_FAILED', {
                action,
                userId,
                timestamp: Date.now()
            });

            return {
                success: false,
                error: 'Aktionsverifizierung fehlgeschlagen - bitte Systemzustand prüfen'
            };
        }

        return {
            success: true,
            action: action,
            verified: true
        };
    }

    async verifyAccessGranted(userId) {
        const user = await getUser(userId);
        return user.permission === 'full_access';
    }

    async verifyAccessRevoked(userId) {
        const user = await getUser(userId);
        return user.permission === 'no_access';
    }
}
# Korrigiert: Formularübermittlung mit Aktionsverifizierung
class SecureDataForm:
    ACTION_MAP = {
        'encrypt': ('encrypt_data', lambda d: d.is_encrypted),
        'decrypt': ('decrypt_data', lambda d: not d.is_encrypted),
        'delete_selected': ('delete_selected', lambda d: d.selected_deleted),
    }

    def handle_submit(self, form_data, operation):
        if operation not in self.ACTION_MAP:
            raise ValueError(f"Unbekannte Operation: {operation}")

        method_name, verify_func = self.ACTION_MAP[operation]
        method = getattr(self, method_name)

        # Korrigiert: Beabsichtigte Operation protokollieren
        logger.info(f"Operation wird ausgeführt: {operation}")

        # Korrigiert: Korrekte Methode ausführen
        result = method(form_data)

        # Korrigiert: Operationsergebnis verifizieren
        if not verify_func(result):
            logger.error(f"Operationsverifizierung fehlgeschlagen: {operation}")
            raise OperationError(f"{operation} Verifizierung fehlgeschlagen")

        logger.info(f"Operation verifiziert: {operation}")
        return result

    def encrypt_data(self, data):
        encrypted = self._perform_encryption(data)
        encrypted.is_encrypted = True
        return encrypted

    def decrypt_data(self, data):
        decrypted = self._perform_decryption(data)
        decrypted.is_encrypted = False
        return decrypted

    def process_file_operation(self, filename, action):
        # Korrigiert: Aktionskonstanten verwenden
        if action == FileAction.MAKE_PUBLIC:
            self.set_public(filename)
            # Korrigiert: Verifizieren, dass Berechtigung korrekt gesetzt wurde
            if not self.is_public(filename):
                raise OperationError("Datei könnte nicht öffentlich gemacht werden")

        elif action == FileAction.MAKE_PRIVATE:
            self.set_private(filename)
            # Korrigiert: Verifizieren, dass Berechtigung korrekt gesetzt wurde
            if not self.is_private(filename):
                raise OperationError("Datei könnte nicht privat gemacht werden")

        return f"Datei {filename}: {action} verifiziert"
// Korrigiert: Firewall-Regeln mit Richtungsverifizierung
public class SecureFirewallUI {

    public FirewallResult applyRule(FirewallRule rule) {
        Direction direction = rule.getDirection();
        int port = rule.getPort();

        // Korrigiert: Klare Aktionszuordnung
        if (direction == Direction.INBOUND) {
            blockInbound(port);
        } else if (direction == Direction.OUTBOUND) {
            blockOutbound(port);
        }

        // Korrigiert: Verifizieren, dass Regel korrekt angewendet wurde
        FirewallState state = getCurrentFirewallState();

        boolean verified = false;
        if (direction == Direction.INBOUND) {
            verified = state.isInboundBlöcked(port);
        } else if (direction == Direction.OUTBOUND) {
            verified = state.isOutboundBlöcked(port);
        }

        if (!verified) {
            // Korrigiert: Verifizierungsfehler melden
            logError("Firewall-Regelverifizierung fehlgeschlagen", rule);
            return FirewallResult.verificationFailed(rule);
        }

        logRuleApplication(rule);
        return FirewallResult.success(rule);
    }

    public ToggleResult toggleFeature(String feature, boolean enable) {
        // Korrigiert: Aktions-Enum verwenden um Verwechslungen zu verhindern
        FeatureAction action = enable ? FeatureAction.ENABLE : FeatureAction.DISABLE;

        switch (feature) {
            case "intrusion_detection":
                return toggleIDS(action);

            case "logging":
                return toggleLogging(action);

            default:
                return ToggleResult.unknownFeature(feature);
        }
    }

    private ToggleResult toggleIDS(FeatureAction action) {
        if (action == FeatureAction.ENABLE) {
            enableIDS();
            // Korrigiert: Verifizieren, dass IDS tatsächlich aktiviert ist
            if (!isIDSEnabled()) {
                return ToggleResult.verificationFailed("IDS aktivieren");
            }
        } else {
            disableIDS();
            // Korrigiert: Verifizieren, dass IDS tatsächlich deaktiviert ist
            if (isIDSEnabled()) {
                return ToggleResult.verificationFailed("IDS deaktivieren");
            }
        }

        return ToggleResult.success(action);
    }
}
// Korrigiert: Kommandozeilen-Tool mit korrekter Aktions-Implementierung
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>

typedef enum { ACTION_ENABLE, ACTION_DISABLE } Action;

// Korrigiert: Aktions-Struct verbindet Option mit korrekter Funktion und Verifizierung
typedef struct {
    const char *option;
    void (*action_func)(void);
    int (*verify_func)(void);
    const char *success_msg;
    const char *failure_msg;
} OptionAction;

int verify_encryption_enabled(void) {
    return is_encryption_active();
}

int verify_logging_disabled(void) {
    return !is_logging_active();
}

// Korrigiert: Klare Zuordnung zwischen Optionen und Aktionen
OptionAction options[] = {
    {
        "--enable-encryption",
        enable_encryption,      // Korrekte Funktion
        verify_encryption_enabled,
        "Verschlüsselung aktiviert und verifiziert",
        "Verschlüsselungsaktivierung-Verifizierung fehlgeschlagen"
    },
    {
        "--disable-logging",
        disable_logging,        // Korrekte Funktion
        verify_logging_disabled,
        "Logging deaktiviert und verifiziert",
        "Logging-Deaktivierung-Verifizierung fehlgeschlagen"
    }
};

void process_options(int argc, char *argv[]) {
    for (int i = 1; i < argc; i++) {
        for (size_t j = 0; j < sizeof(options)/sizeof(options[0]); j++) {
            if (strcmp(argv[i], options[j].option) == 0) {
                // Korrigiert: Aktion ausführen
                options[j].action_func();

                // Korrigiert: Aktionsergebnis verifizieren
                if (options[j].verify_func()) {
                    printf("%s\n", options[j].success_msg);
                } else {
                    fprintf(stderr, "FEHLER: %s\n", options[j].failure_msg);
                    exit(1);
                }
                break;
            }
        }
    }
}

// Korrigiert: Berechtigungssetzung mit Verifizierung
int set_file_permissions(const char *filename, const char *mode) {
    mode_t target_mode;

    if (strcmp(mode, "private") == 0) {
        target_mode = 0600;
    } else if (strcmp(mode, "public") == 0) {
        target_mode = 0644;
    } else {
        fprintf(stderr, "Unbekannter Modus: %s\n", mode);
        return -1;
    }

    // Korrigiert: Berechtigungen setzen
    if (chmod(filename, target_mode) != 0) {
        perror("chmod fehlgeschlagen");
        return -1;
    }

    // Korrigiert: Verifizieren, dass Berechtigungen korrekt gesetzt wurden
    struct stat st;
    if (stat(filename, &st) != 0) {
        perror("stat fehlgeschlagen");
        return -1;
    }

    if ((st.st_mode & 0777) != target_mode) {
        fprintf(stderr, "Berechtigungsverifizierung fehlgeschlagen\n");
        return -1;
    }

    printf("Datei %s auf %s gesetzt (Modus %o verifiziert)\n", filename, mode, target_mode);
    return 0;
}

CVE-Beispiele

  • CVE-2001-1387 - Netzwerk-Firewall implementierte inkorrekte Kommandozeilenoptionen, was potenziell zu Informationslecks führte.
  • CVE-2001-0081 - Benutzerabfragen wurden unterdrückt, aber zugrunde liegende Funktionen blieben trotz Spezifikationsanforderungen aktiv.
  • CVE-2002-1977 - Timeout-Funktionalität arbeitete nicht gemäß Benutzerspezifikationen, wodurch sensible Daten über die beabsichtigte Dauer hinaus exponiert wurden.

Referenzen

  1. MITRE Corporation. "CWE-449: The UI Performs the Wrong Action." https://cwe.mitre.org/data/definitions/449.html
  2. OWASP Testing Guide. "Business Logic Testing."