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
| Auswirkung | Details |
|---|---|
| Sicherheit | Bereich: Umgehung Benutzer deaktivieren oder umgehen Sicherheitskontrollen. |
| Authentifizierung | Bereich: Schwache Anmeldedaten Komplexe Regeln führen zu vorhersagbaren Passwörtern. |
| Schulung | Bereich: 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
-
MITRE. "CWE-655: Insufficient Psychological Acceptability." https://cwe.mitre.org/data/definitions/655.html
-
NIST SP 800-63B. "Digital Identity Guidelines."