Unzureichende psychologische Akzeptanz

Beschreibung

Unzureichende psychologische Akzeptanz tritt auf, wenn Sicherheitsmechanismen so schwierig, verwirrend oder frustrierend in der Verwendung sind, dass Benutzer sie umgehen, deaktivieren oder Workarounds finden. Sicherheitskontrollen müssen benutzbar und verständlich sein, um wirksam zu sein. Übermäßig komplexe Passwortanforderungen, aufdringliche Authentifizierung, verwirrende Berechtigungsdialoge und schlecht gestaltete Sicherheits-UX führen dazu, dass Benutzer unsichere Workarounds finden.

Risiko

Benutzer erstellen schwache Passwörter, die komplexe Regeln nur oberflächlich erfüllen. Sicherheitswarnungen werden aufgrund von Warnungsmüdigkeit ignoriert. Benutzer teilen Anmeldedaten, um wiederholte Authentifizierung zu vermeiden. Sicherheitsfunktionen werden deaktiviert, um den Arbeitsablauf zu verbessern. Phishing-Angriffe sind erfolgreich, weil Benutzer darauf konditioniert sind, Warnungen wegzuklicken. Schatten-IT entsteht, um sichere aber unbenutzbare Systeme zu umgehen.

Lösung

Gestalten Sie Sicherheit, die sich an Benutzer-Workflows orientiert. Implementieren Sie progressive Sicherheit (stärker bei sensiblen Aktionen). Verwenden Sie klare, handlungsorientierte Sicherheitsnachrichten. Reduzieren Sie Reibung für legitime Nutzung bei gleichzeitiger Aufrechterhaltung der Sicherheit. Führen Sie Usability-Tests von Sicherheitskontrollen durch. Bieten Sie sichere Standardeinstellungen, die minimale Benutzerinteraktion erfordern.

Häufige Auswirkungen

AuswirkungDetails
SicherheitBereich: Umgehung

Benutzer deaktivieren oder umgehen Sicherheitskontrollen.
AuthentifizierungBereich: Schwache Anmeldedaten

Komplexe Regeln führen zu vorhersagbaren Passwörtern.
SchulungBereich: Warnungsmüdigkeit

Benutzer ignorieren Sicherheitswarnungen.

Beispielcode und Lösung

Verwundbarer Code

// VERWUNDBAR: Übermäßig komplexe Passwortanforderungen
public class UnusablePasswordValidator {

    public ValidationResult validatePassword(String password) {
        List<String> errors = new ArrayList<>();

        // VERWUNDBAR: So viele Regeln, dass Benutzer Passwörter aufschreiben
        if (password.length() < 16) {
            errors.add("Password must be at least 16 characters");
        }
        if (password.length() > 20) {
            errors.add("Password must be at most 20 characters");
        }
        if (!password.matches(".*[A-Z].*")) {
            errors.add("Must contain uppercase letter");
        }
        if (!password.matches(".*[a-z].*")) {
            errors.add("Must contain lowercase letter");
        }
        if (!password.matches(".*[0-9].*")) {
            errors.add("Must contain number");
        }
        if (!password.matches(".*[!@#$%^&*()].*")) {
            errors.add("Must contain special character from: !@#$%^&*()");
        }
        if (password.matches(".*(.)(\\1{2,}).*")) {
            errors.add("No character can repeat more than twice");
        }
        if (password.matches(".*(012|123|234|345|456|567|678|789).*")) {
            errors.add("No sequential numbers allowed");
        }
        if (password.matches(".*(abc|bcd|cde|def|efg).*")) {
            errors.add("No sequential letters allowed");
        }
        // Muss alle 30 Tage geändert werden
        // Darf die letzten 24 Passwörter nicht wiederverwenden

        // Ergebnis: Benutzer erstellen "Password1!"-Variationen und schreiben sie auf

        return new ValidationResult(errors.isEmpty(), errors);
    }
}

// VERWUNDBAR: Ständige Sicherheitsunterbrechungen
public class IntrusiveSecurityController {

    @RequestMapping("/**")
    public Object handleAllRequests(HttpServletRequest request) {
        // VERWUNDBAR: Erneute Authentifizierung bei jeder Aktion
        if (!authenticateUser(request)) {
            return redirectToLogin();  // Benutzer teilen Passwörter, um dies zu vermeiden
        }

        // VERWUNDBAR: CAPTCHA bei jedem Formular
        if (!verifyCaptcha(request)) {
            return showCaptcha();  // Benutzer finden Workarounds
        }

        // VERWUNDBAR: Sicherheitsfrage für jede sensible Seite
        if (isSensitivePage(request)) {
            return askSecurityQuestion();  // Benutzer wählen einfache Fragen
        }

        return processRequest(request);
    }
}

// VERWUNDBAR: Verwirrende Sicherheitswarnungen
public class ConfusingSecurityWarnings {

    public void showCertificateWarning() {
        // VERWUNDBAR: Technischer Jargon, den Benutzer nicht verstehen
        showDialog(
            "SSL/TLS Certificate Error: " +
            "The certificate chain validation failed. " +
            "ERR_CERT_AUTHORITY_INVALID (0x800B0109). " +
            "The certificate is not signed by a trusted authority. " +
            "SHA-256 fingerprint: a4:b2:c1:d3:e5...",
            "Proceed Anyway", "Cancel"
        );
        // Benutzer lernen, bei allem auf "Trotzdem fortfahren" zu klicken
    }
}
# VERWUNDBAR: Passwortrichtlinie, die zu unsicherem Verhalten führt
class UnusablePasswordPolicy:
    def validate(self, password):
        errors = []

        # VERWUNDBAR: Widersprüchliche/unmögliche Regeln
        if len(password) < 14:
            errors.append("Minimum 14 characters")
        if len(password) > 16:
            errors.append("Maximum 16 characters")

        # Erfordert Komplexität, die vorhersagbare Muster erzwingt
        if not re.search(r'[A-Z]', password):
            errors.append("Needs uppercase")
        if not re.search(r'[a-z]', password):
            errors.append("Needs lowercase")
        if not re.search(r'[0-9]', password):
            errors.append("Needs number")
        if not re.search(r'[!@#$%^&*]', password):
            errors.append("Needs special character")

        # Keine gängigen Wörter - aber Benutzer hängen einfach 1! an gängige Wörter an
        common_words = ['password', 'company', 'admin', 'user']
        for word in common_words:
            if word.lower() in password.lower():
                errors.append(f"Cannot contain '{word}'")

        # VERWUNDBAR: 24-Passwort-Verlauf führt zu Post-it-Zetteln
        if password in self.get_password_history(user_id, count=24):
            errors.append("Cannot reuse recent passwords")

        return len(errors) == 0, errors

# VERWUNDBAR: Session-Timeout zu aggressiv
class IntrusiveSessionManager:
    def __init__(self):
        # VERWUNDBAR: 5-Minuten-Timeout verursacht ständiges erneutes Einloggen
        self.session_timeout = 300  # Sekunden

    def check_session(self, session):
        if time.time() - session.last_activity > self.session_timeout:
            # Benutzer bleiben an gemeinsam genutzten Computern eingeloggt, um dies zu vermeiden
            session.invalidate()
            return False
        return True

# VERWUNDBAR: Übermäßig ausführliche Sicherheitsstatus-Dialoge
def show_security_status():
    # VERWUNDBAR: Informationsüberflutung
    message = """
    Security Status Report:
    - TLS 1.3 connection established
    - Certificate: Valid (expires 2024-12-31)
    - OCSP: Verified
    - CT: 3 SCTs present
    - HSTS: Enabled (max-age=31536000)
    - CSP: strict-dynamic enforced
    - X-Frame-Options: DENY
    - Referrer-Policy: strict-origin-when-cross-origin
    ...
    [50 weitere technische Details]

    Do you want to continue?
    """
    # Benutzer lernen, durchzuklicken, ohne zu lesen
    return show_dialog(message, ["Yes", "No"])
// VERWUNDBAR: Ständige Unterbrechungen
class IntrusiveSecurityUI {
    constructor() {
        this.lastCaptchaTime = 0;
    }

    // VERWUNDBAR: CAPTCHA bei jeder Aktion
    async performAction(action) {
        // Benutzer werden frustriert und verlassen die Seite
        await this.showCaptcha();

        // Dann Sicherheitsfrage
        await this.askSecurityQuestion();

        // Dann MFA
        await this.verifyMFA();

        // Erst dann die Aktion ausführen
        return action();
    }

    // VERWUNDBAR: Warndialoge, die Benutzer zum Durchklicken trainieren
    showSecurityWarning() {
        // Technischer Jargon und beängstigende Sprache
        return showModal({
            title: '⚠️ CRITICAL SECURITY WARNING ⚠️',
            message: `
                Your connection may be compromised!
                Error Code: SEC_ERROR_UNKNOWN_ISSUER
                The certificate is not trusted because no issuer chain was provided.
                Technical Details: Certificate chain incomplete. OCSP response indicates...
                [200 weitere Wörter technischer Inhalt]
            `,
            buttons: ['I understand the risks, proceed anyway', 'Go back to safety']
        });
        // Benutzer lernen, immer auf "fortfahren" zu klicken
    }

    // VERWUNDBAR: Passwortänderung wird zu häufig erzwungen
    enforcePasswordChange(user) {
        const daysSinceChange = (Date.now() - user.passwordChangedAt) / 86400000;
        if (daysSinceChange > 30) {
            // Benutzer inkrementieren Nummer: Password1! -> Password2! -> Password3!
            this.forcePasswordChange();
        }
    }
}

// VERWUNDBAR: Verwirrende Berechtigungsanfragen
function requestPermissions() {
    // Benutzer verstehen nicht, worauf sie sich einlassen
    return showPermissionDialog({
        title: 'Permission Required',
        message: 'This app needs the following permissions: ' +
                 'READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE, ' +
                 'ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION, ' +
                 'READ_CONTACTS, WRITE_CONTACTS, CAMERA, MICROPHONE, ' +
                 'SYSTEM_ALERT_WINDOW, REQUEST_INSTALL_PACKAGES...',
        buttons: ['Allow All', 'Deny']
    });
    // Benutzer klicken auf "Alle erlauben", damit es verschwindet
}

Sichere Lösung

// SICHER: Benutzerfreundliche Passwortanforderungen
public class UsablePasswordValidator {

    public ValidationResult validatePassword(String password) {
        // SICHER: Fokus auf Länge statt Komplexität
        // Forschung zeigt, dass Länge sicherer ist als Komplexitätsregeln

        if (password.length() < 12) {
            return ValidationResult.fail(
                "Password needs at least 12 characters. " +
                "Tip: Try a memorable phrase like 'correct horse battery staple'"
            );
        }

        // Gegen bekannte Datenlecks prüfen (nicht willkürliche Regeln)
        if (isBreachedPassword(password)) {
            return ValidationResult.fail(
                "This password has appeared in data breaches. " +
                "Please choose a different password for your security."
            );
        }

        // Einfacher Stärkemesser - keine blockierenden Regeln
        int strength = calculateStrength(password);
        String strengthMessage = getStrengthFeedback(strength);

        return ValidationResult.success(strengthMessage);
    }

    // SICHER: Klares, handlungsorientiertes Feedback
    private String getStrengthFeedback(int strength) {
        if (strength >= 80) {
            return "Starkes Passwort";
        } else if (strength >= 60) {
            return "Gutes Passwort - erwägen Sie es länger zu machen für extra Sicherheit";
        } else {
            return "Akzeptabel - mehr Wörter hinzuzufügen würde es stärker machen";
        }
    }
}

// SICHER: Progressive Sicherheit
public class ProgressiveSecurityController {

    @RequestMapping("/**")
    public Object handleRequest(HttpServletRequest request) {
        // Aktionen mit geringem Risiko: minimale Reibung
        if (isLowRiskAction(request)) {
            return processRequest(request);
        }

        // Mittleres Risiko: Prüfen ob Session aktiv ist
        if (isMediumRiskAction(request)) {
            if (!sessionService.isActive(request)) {
                return redirectToLogin();
            }
            return processRequest(request);
        }

        // Hohes Risiko: Step-up-Authentifizierung
        if (isHighRiskAction(request)) {
            if (!hasRecentAuthentication(request, Duration.ofMinutes(5))) {
                return requestReauthentication();
            }
            return processRequest(request);
        }

        return processRequest(request);
    }
}

// SICHER: Klare, benutzerfreundliche Sicherheitswarnungen
public class UserFriendlySecurityWarnings {

    public void showCertificateWarning(CertificateError error) {
        // SICHER: Einfache Sprache, klare Aktionen
        if (error.isSelfSigned()) {
            showDialog(
                "Das Sicherheitszertifikat dieser Website wurde nicht von einer " +
                "vertrauenswürdigen Organisation ausgestellt.\n\n" +
                "Dies könnte bedeuten:\n" +
                "• Sie befinden sich auf einer Test- oder internen Seite (in Ordnung)\n" +
                "• Jemand versucht möglicherweise, Ihre Daten abzufangen (nicht in Ordnung)\n\n" +
                "Wenn Sie unsicher sind, fahren Sie nicht fort.",
                "Zurück (empfohlen)",
                "Ich verstehe, trotzdem fortfahren"
            );
        }
    }
}
# SICHER: Benutzerfreundliche Passwortrichtlinie
class UsablePasswordPolicy:
    def validate(self, password, username=None):
        # SICHER: Einfache Längenanforderung
        if len(password) < 12:
            return False, "Bitte verwenden Sie mindestens 12 Zeichen. Passphrasen funktionieren hervorragend!"

        # Gegen bekannte kompromittierte Passwörter prüfen
        if self.is_breached(password):
            return False, (
                "Dieses Passwort erscheint in bekannten Datenlecks. "
                "Bitte wählen Sie ein anderes, um sicher zu bleiben."
            )

        # Offensichtliche Muster verhindern (nicht willkürliche Komplexität)
        if username and username.lower() in password.lower():
            return False, "Passwort sollte nicht Ihren Benutzernamen enthalten"

        # SICHER: Hilfreiche Stärke-Rückmeldung statt Blockierung
        strength = self.estimate_strength(password)

        if strength >= 3:
            return True, "Starkes Passwort"
        elif strength >= 2:
            return True, "Gutes Passwort. Mehr Wörter hinzuzufügen würde es noch besser machen."
        else:
            return True, "Akzeptables Passwort"

    def is_breached(self, password):
        # Gegen HaveIBeenPwned oder lokale Breach-Datenbank prüfen
        password_hash = hashlib.sha1(password.encode()).hexdigest()
        return self.breach_db.contains(password_hash[:5])

# SICHER: Vernünftiges Session-Management
class UsableSessionManager:
    def __init__(self):
        # SICHER: Vernünftiges Timeout mit Aktivitätsverlängerung
        self.idle_timeout = 3600  # 1 Stunde für normale Seiten
        self.sensitive_timeout = 300  # 5 Min für sensible Seiten
        self.absolute_timeout = 86400  # 24 Stunden Maximum

    def check_session(self, session, is_sensitive=False):
        timeout = self.sensitive_timeout if is_sensitive else self.idle_timeout

        idle_time = time.time() - session.last_activity
        if idle_time > timeout:
            # SICHER: Erklären warum und einfache erneute Authentifizierung anbieten
            return {
                'valid': False,
                'message': f"Bitte melden Sie sich zu Ihrer Sicherheit erneut an. "
                          f"Sie waren {int(idle_time/60)} Minuten inaktiv."
            }

        # Aktivität bei Aktion verlängern
        session.last_activity = time.time()
        return {'valid': True}

# SICHER: Progressive Authentifizierung
class ProgressiveAuth:
    def get_required_auth_level(self, action):
        # Verschiedene Aktionen benötigen verschiedene Sicherheitsstufen
        LOW_RISK = ['view_profile', 'browse', 'read']
        MEDIUM_RISK = ['update_profile', 'change_settings']
        HIGH_RISK = ['change_password', 'transfer_funds', 'delete_account']

        if action in HIGH_RISK:
            return 'reauthenticate'  # Passwort + MFA
        elif action in MEDIUM_RISK:
            return 'session'  # Gültige Session
        else:
            return 'none'  # Öffentlicher Zugriff

    def verify_auth(self, user, action, credentials=None):
        required = self.get_required_auth_level(action)

        if required == 'none':
            return True

        if required == 'session':
            return user.session.is_valid()

        if required == 'reauthenticate':
            # Nur bei wirklich sensiblen Aktionen nach erneuter Authentifizierung fragen
            return self.verify_credentials(user, credentials)
// SICHER: Benutzerfreundliche Sicherheit in JavaScript
class UserFriendlySecurity {

    // SICHER: Klare, einfache Passwortanleitung
    validatePassword(password, email) {
        // Länge ist entscheidend - NIST empfiehlt 8+ Minimum, wir schlagen 12+ vor
        if (password.length < 12) {
            return {
                valid: false,
                message: 'Bitte verwenden Sie mindestens 12 Zeichen. Probieren Sie einen Satz, den Sie sich merken können!',
                suggestion: 'Beispiel: "purple elephant jumps high"'
            };
        }

        // Kompromittierte Passwörter prüfen
        if (this.isBreached(password)) {
            return {
                valid: false,
                message: 'Dieses Passwort wurde in einem Datenleck gefunden. Bitte verwenden Sie ein anderes.'
            };
        }

        // Hilfreich, nicht blockierend
        const strength = this.measureStrength(password);
        return {
            valid: true,
            strength,
            message: this.getStrengthMessage(strength)
        };
    }

    getStrengthMessage(strength) {
        const messages = {
            'strong': 'Hervorragendes Passwort!',
            'good': 'Gutes Passwort',
            'ok': 'Akzeptabel - länger wäre besser'
        };
        return messages[strength];
    }

    // SICHER: Klartext-Sicherheitswarnungen
    showSecurityWarning(type, details) {
        const warnings = {
            'certificate': {
                title: 'Sicherheitswarnung',
                message: `
                    Wir können die Identität dieser Website nicht überprüfen.

                    Das könnte bedeuten:
                    • Die Seite ist falsch konfiguriert
                    • Jemand könnte Ihre Verbindung abfangen

                    Was soll ich tun?
                    • Wenn Sie dies erwartet haben (z.B. eine firmeninterne Seite), kann es in Ordnung sein
                    • Wenn nicht, gehen Sie zu Ihrer Sicherheit zurück
                `,
                primaryAction: 'Zurück',
                secondaryAction: 'Ich verstehe, fortfahren'
            },
            'unsaved': {
                title: 'Ungespeicherte Änderungen',
                message: 'Sie haben ungespeicherte Änderungen. Trotzdem verlassen?',
                primaryAction: 'Bleiben',
                secondaryAction: 'Ohne Speichern verlassen'
            }
        };

        return showDialog(warnings[type]);
    }

    // SICHER: Progressive Sicherheit basierend auf Risiko
    async performAction(action, context) {
        const riskLevel = this.assessRisk(action, context);

        if (riskLevel === 'low') {
            return await action();
        }

        if (riskLevel === 'medium') {
            // Nur prüfen, ob Session aktiv ist
            if (!this.isSessionActive()) {
                await this.showQuickReauth();
            }
            return await action();
        }

        if (riskLevel === 'high') {
            // Vollständige erneute Authentifizierung mit klarer Erklärung
            const reauth = await this.showReauthDialog({
                message: 'Diese Aktion betrifft Ihre Kontosicherheit. ' +
                         'Bitte bestätigen Sie Ihr Passwort.',
                reason: action.description
            });

            if (reauth.success) {
                return await action();
            }
        }
    }
}

Ausgenutzt in der Praxis

Passwortmuster

Komplexe Regeln führen zu "Password1!"-Mustern.

Warnungsmüdigkeit

Benutzer, die darauf trainiert wurden, Warnungen wegzuklicken, fallen auf Phishing herein.

Teilen von Anmeldedaten

Aufdringliche Authentifizierung führt zum Teilen von Passwörtern.


Tools zum Testen und Ausnutzen

  • Usability-Testing-Frameworks.

  • Passwortmuster-Analyse.

  • Benutzerverhaltensanalyse.


CVE-Beispiele

  • Sicherheitsumgehungen durch Benutzer-Workarounds.

  • Phishing-Erfolg durch Warnungsmüdigkeit.


Referenzen

  1. MITRE. "CWE-655: Insufficient Psychological Acceptability." https://cwe.mitre.org/data/definitions/655.html

  2. NIST SP 800-63B. "Digital Identity Guidelines."