Unzureichende Typunterscheidung
Beschreibung
Unzureichende Typunterscheidung ist eine Schwachstelle, die auftritt, wenn ein Produkt nicht ordnungsgemäß zwischen verschiedenen Arten von Elementen unterscheidet, was zu unsicherem Verhalten führt. Diese Schwäche manifestiert sich, wenn Anwendungen es versäumen, zwischen unterschiedlichen Datentypen, Ereignistypen, Objekttypen oder anderen kategorialen Unterscheidungen zu differenzieren, die sicherheitsrelevante Auswirkungen haben. Häufige Beispiele umfassen das Versäumnis, zwischen benutzer-initiierten Ereignissen und programmatisch generierten (synthetischen) Ereignissen in Benutzeroberflächen zu unterscheiden, verschiedene Dateitypen als äquivalent zu behandeln, wenn sie unterschiedliche Sicherheitseigenschaften haben, nicht zwischen authentifizierten und nicht authentifizierten Anfragen zu differenzieren und Elemente basierend auf partiellen Attributen anstelle vollständiger Typinformationen zu vergleichen. Das Ergebnis ist, dass Sicherheitsmechanismen, die für einen Elementtyp konzipiert sind, umgangen werden können, indem ein anderer Typ substituiert wird, den die Anwendung fälschlicherweise als äquivalent behandelt.
Risiko
Unzureichende Typunterscheidung ermöglicht Angreifern, Sicherheitskontrollen zu umgehen, indem sie das Versagen der Anwendung ausnutzen, zwischen Typen zu differenzieren. In Browser-Kontexten ermöglicht das Versäumnis, zwischen benutzer-initiierten Klicks und synthetischen JavaScript-Ereignissen zu unterscheiden, Clickjacking und automatisierte UI-Interaktionsangriffe. Dateiupload-Systeme, die Dateitypen nicht ordnungsgemäß durch ihren tatsächlichen Inhalt unterscheiden, können erlauben, dass ausführbare Dateien als Bilder hochgeladen werden. Zugriffskontrollsysteme, die nicht zwischen Anforderungstypen unterscheiden, können Berechtigungen falsch anwenden. Wenn Anwendungen Objekte basierend auf unvollständigen Attributen vergleichen, können Angreifer Objekte erstellen, die privilegierten Objekten ähnlich erscheinen, es aber nicht sind, was zu Privilegien-Eskalation oder Datenverlust führt. Das Risiko wird verstärkt, wenn die Typunterscheidung sicherheitskritische Entscheidungen wie Autorisierung, Dateiverwaltung oder Ereignisverarbeitung beeinflusst, wo die Folgen einer Fehlklassifizierung schwerwiegend sein können.
Lösung
Implementieren Sie strikte Typprüfung und -validierung in der gesamten Anwendung. In Benutzeroberflächen verifizieren Sie, dass Ereignisse wirklich benutzer-initiiert sind, bevor sicherheitsrelevante Aktionen verarbeitet werden. Für Dateiverwaltung validieren Sie Dateien nach Inhalt anstatt Erweiterung und pflegen Sie explizite Typinformationen. Beim Vergleichen von Objekten für Sicherheitszwecke vergleichen Sie alle relevanten Attribute einschließlich derer, die Typen unterscheiden. Verwenden Sie starke Typisierung in Programmiersprachen, wo verfügbar, und validieren Sie Typen explizit, wenn starke Typisierung nicht durchgesetzt wird. Implementieren Sie separate Code-Pfade für die Handhabung verschiedener Typen, anstatt zu versuchen, alle Typen generisch zu behandeln. Dokumentieren Sie die Sicherheitsimplikationen von Typunterscheidungen und stellen Sie sicher, dass alle Entwickler verstehen, wann Typprüfung sicherheitskritisch ist. Verwenden Sie explizite Typmarkierungen, die von Angreifern nicht gefälscht werden können.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Zugriffskontrolle | Umfang: Zugriffskontrolle Das Versäumnis, zwischen Benutzertypen, Anforderungstypen oder Berechtigungsstufen zu unterscheiden, kann unbefugten Zugriff oder Privilegien-Eskalation ermöglichen. |
| Integrität | Umfang: Integrität Falsche Typbehandlung kann zu Datenkorruption, Verlust von Zugriffskontrolllisten oder unsachgemäßer Änderung sensibler Daten führen. |
| Sonstige | Umfang: Sonstige Das Versäumnis, Ereignistypen zu unterscheiden, ermöglicht UI-Manipulation, Clickjacking und automatisierte Interaktionsangriffe, die die Benutzereinwilligung umgehen. |
Beispielcode
Anfälliger Code (JavaScript/Python)
Die folgenden Beispiele demonstrieren unzureichende Typunterscheidung:
// Anfällig: Keine Unterscheidung zwischen Benutzer- und synthetischen Ereignissen
document.getElementById('deleteButton').addEventListener('click', function(event) {
// Anfällig: Nicht prüfend ob Ereignis benutzer-initiiert ist
// Synthetische Ereignisse können dies auslösen
performDeletion();
});
// Anfällig: Formularübermittlung ohne Ereignistypprüfung
document.querySelector('form').addEventListener('submit', function(event) {
// Anfällig: Skript-generierte Submit-Ereignisse werden wie Benutzer behandelt
submitForm();
});
// Anfällig: Alle Dateitypen gleich behandeln
function vulnerableUploadFile(file) {
// Anfällig: Nur Erweiterung prüfen, nicht tatsächlichen Typ
if (file.name.endsWith('.jpg') || file.name.endsWith('.png')) {
uploadImage(file); // Könnte ausführbar mit falscher Erweiterung sein
}
}
// Anfällig: Keine Unterscheidung zwischen Anfragequellen
app.post('/api/delete', (req, res) => {
// Anfällig: Same-Origin und Cross-Origin Anfragen werden identisch behandelt
// Kein CSRF-Token oder Origin-Prüfung
deleteResource(req.body.id);
});
// Anfällig: Objektvergleich mit unvollständigen Attributen
function vulnerableCheckPermission(user, requiredRole) {
// Anfällig: Nur Rollenname prüfen, nicht Rollenquelle/-gültigkeit
if (user.role === requiredRole) {
return true; // Angreifer kann user.role auf beliebigen String setzen
}
return false;
}
// Anfällig: Session-Typ nicht unterschieden
function vulnerableGetSession(sessionId) {
const session = sessions.get(sessionId);
// Anfällig: Nicht prüfend ob Session Admin vs Benutzer-Typ ist
// oder ob Session temporär vs persistent ist
return session;
}
// Anfällig: Nachrichtentyp-Verwirrung
window.addEventListener('message', function(event) {
const data = event.data;
// Anfällig: Nachrichtentypen nicht ordnungsgemäß unterscheiden
if (data.action === 'transfer') {
// Könnte legitime App-Nachricht oder Frame des Angreifers sein
performTransfer(data.amount, data.recipient);
}
});
# Anfällig: Unzureichende Typunterscheidung in Python
from flask import Flask, request
import os
app = Flask(__name__)
# Anfällig: Keine Dateityp-Validierung
@app.route('/upload', methods=['POST'])
def vulnerable_upload():
file = request.files['file']
# Anfällig: Dateinamen-Erweiterung vertrauen
if file.filename.endswith(('.jpg', '.png', '.gif')):
# Angreifer lädt PHP-Datei als image.jpg hoch
file.save(os.path.join('/uploads/', file.filename))
return 'Hochgeladen'
return 'Ungültiger Dateityp', 400
# Anfällig: Objekttyp-Verwirrung
class VulnerablePermissionCheck:
def check_access(self, user_obj, resource):
# Anfällig: Nur Attribut prüfen, nicht Objekttyp
if hasattr(user_obj, 'is_admin') and user_obj.is_admin:
return True # Angreifer erstellt Dict mit is_admin=True
return False
# Anfällig: Anforderungstyp nicht unterschieden
@app.route('/api/sensitive', methods=['GET', 'POST'])
def vulnerable_api():
# Anfällig: GET und POST werden gleich behandelt
# GET-Anfragen könnten CSRF-Schutz umgehen
return handle_sensitive_action(request.values)
# Anfällig: Unvollständige Attributvergleiche
class User:
def __init__(self, id, name, role):
self.id = id
self.name = name
self.role = role
def vulnerable_compare_users(user1, user2):
# Anfällig: Nur Name und Rolle vergleichen, nicht ID
# Zwei verschiedene Benutzer mit gleichem Namen/Rolle werden als identisch behandelt
return user1.name == user2.name and user1.role == user2.role
# Anfällig: Token-Typ-Verwirrung
def vulnerable_verify_token(token):
# Anfällig: Nicht zwischen Access- und Refresh-Tokens unterscheiden
decoded = jwt.decode(token, SECRET_KEY, algorithms=['HS256'])
# Angreifer verwendet Refresh-Token als Access-Token
return decoded.get('user_id')
Korrigierter Code (JavaScript/Python)
// Korrigiert: Ordnungsgemäße Typunterscheidung
document.getElementById('deleteButton').addEventListener('click', function(event) {
// Korrigiert: Prüfen ob Ereignis vertrauenswürdig (benutzer-initiiert) ist
if (!event.isTrusted) {
console.warn('Synthetisches Ereignis blockiert');
return;
}
// Korrigiert: Zusätzliche Prüfung auf kürzliche Benutzerinteraktion
if (!isUserInteractionRecent()) {
return;
}
performDeletion();
});
// Korrigiert: Formularübermittlung mit Ereignisvalidierung
document.querySelector('form').addEventListener('submit', function(event) {
// Korrigiert: Vertrauenswürdiges Ereignis verifizieren
if (!event.isTrusted) {
event.preventDefault();
return;
}
// Korrigiert: Auf versteckte Formularübermittlungen prüfen
if (!document.hasFocus()) {
event.preventDefault();
return;
}
submitForm();
});
// Korrigiert: Dateityp-Validierung nach Inhalt
async function secureUploadFile(file) {
// Korrigiert: Tatsächlichen Dateiinhalt prüfen, nicht nur Erweiterung
const buffer = await file.arrayBuffer();
const bytes = new Uint8Array(buffer.slice(0, 4));
// Magic Bytes prüfen
const isJpeg = bytes[0] === 0xFF && bytes[1] === 0xD8;
const isPng = bytes[0] === 0x89 && bytes[1] === 0x50 && bytes[2] === 0x4E;
if (!isJpeg && !isPng) {
throw new Error('Ungültiger Dateityp');
}
// Korrigiert: Auch serverseitig validieren
uploadImage(file);
}
// Korrigiert: Anfrage-Origin-Unterscheidung
app.post('/api/delete', csrfProtection, (req, res) => {
// Korrigiert: CSRF-Token validiert dass Anfrage von unserem Origin stammt
// Korrigiert: Origin-Header prüfen
const origin = req.headers.origin;
if (!allowedOrigins.includes(origin)) {
return res.status(403).send('Verboten');
}
deleteResource(req.body.id);
});
// Korrigiert: Vollständiger Objektvergleich
function secureCheckPermission(user, requiredRole) {
// Korrigiert: Benutzerobjekttyp und -quelle verifizieren
if (!(user instanceof AuthenticatedUser)) {
return false; // Muss ordnungsgemäße User-Instanz sein
}
// Korrigiert: Rollenobjekt prüfen, nicht nur Namen
if (!user.roles || !Array.isArray(user.roles)) {
return false;
}
// Korrigiert: Rollenobjekte mit ordnungsgemäßer Validierung vergleichen
return user.roles.some(role =>
role instanceof Role &&
role.name === requiredRole &&
role.isValid()
);
}
// Korrigiert: Session-Typ-Unterscheidung
function secureGetSession(sessionId, expectedType) {
const session = sessions.get(sessionId);
if (!session) return null;
// Korrigiert: Session-Typ verifizieren
if (session.type !== expectedType) {
return null; // Falscher Session-Typ
}
// Korrigiert: Session-Quelle verifizieren
if (!session.source || session.source !== 'auth_server') {
return null;
}
return session;
}
// Korrigiert: Nachrichtentyp mit Origin-Prüfung
window.addEventListener('message', function(event) {
// Korrigiert: Origin verifizieren
if (!trustedOrigins.includes(event.origin)) {
return;
}
const data = event.data;
// Korrigiert: Nachrichtenstruktur und -typ verifizieren
if (typeof data !== 'object' || data === null) {
return;
}
if (!data.messageType || data.messageType !== 'app_internal') {
return;
}
// Korrigiert: Typspezifische Behandlung
switch(data.action) {
case 'transfer':
if (validateTransferMessage(data)) {
performTransfer(data.amount, data.recipient);
}
break;
}
});
# Korrigiert: Ordnungsgemäße Typunterscheidung in Python
from flask import Flask, request
import magic # python-magic für Dateityperkennung
from functools import wraps
app = Flask(__name__)
# Korrigiert: Inhaltsbasierte Dateityp-Validierung
@app.route('/upload', methods=['POST'])
def secure_upload():
file = request.files['file']
# Korrigiert: Tatsächlichen Dateiinhaltstyp prüfen
file_content = file.read()
mime_type = magic.from_buffer(file_content, mime=True)
allowed_types = {'image/jpeg', 'image/png', 'image/gif'}
if mime_type not in allowed_types:
return 'Ungültiger Dateityp', 400
# Korrigiert: Sicheren Dateinamen generieren
import uuid
safe_filename = f"{uuid.uuid4()}.{mime_type.split('/')[-1]}"
file.seek(0)
file.save(os.path.join('/uploads/', safe_filename))
return 'Hochgeladen'
# Korrigiert: Ordnungsgemäße Typprüfung für Berechtigungen
class SecurePermissionCheck:
def check_access(self, user_obj, resource):
# Korrigiert: Objekttyp explizit verifizieren
if not isinstance(user_obj, AuthenticatedUser):
return False
# Korrigiert: Prüfen dass Attribut existiert und korrekten Typ hat
if not hasattr(user_obj, 'is_admin') or \
not isinstance(user_obj.is_admin, bool):
return False
# Korrigiert: Verifizieren dass Benutzer aus gültiger Quelle stammt
if not user_obj.authenticated_by_server:
return False
return user_obj.is_admin
# Korrigiert: HTTP-Methoden unterscheiden
@app.route('/api/sensitive', methods=['POST'])
@csrf_protect
def secure_api():
# Korrigiert: Nur POST erlaubt, CSRF-Schutz aktiviert
# Korrigiert: Explizite Methodenprüfung
if request.method != 'POST':
return 'Methode nicht erlaubt', 405
return handle_sensitive_action(request.get_json())
# Korrigiert: Vollständiger Objektvergleich
class User:
def __init__(self, id, name, role):
self.id = id
self.name = name
self.role = role
def __eq__(self, other):
# Korrigiert: Alle relevanten Attribute vergleichen
if not isinstance(other, User):
return False
return (self.id == other.id and
self.name == other.name and
self.role == other.role)
# Korrigiert: Token-Typ-Unterscheidung
def secure_verify_token(token, expected_type='access'):
decoded = jwt.decode(token, SECRET_KEY, algorithms=['HS256'])
# Korrigiert: Token-Typ prüfen
token_type = decoded.get('type')
if token_type != expected_type:
raise ValueError(f"Erwartetes {expected_type}-Token, bekam {token_type}")
return decoded.get('user_id')
Die Korrektur implementiert explizite Typprüfung, inhaltsbasierte Validierung und ordnungsgemäße Typunterscheidung für Sicherheitsentscheidungen.
Ausgenutzt in der Praxis
Browser-Ereignis-Spoofing (CVE-2005-2260)
Browser-Benutzeroberfläche unterschied nicht zwischen benutzer-initiierten und synthetischen Ereignissen, was Skripten ermöglichte, Aktionen auszulösen, die scheinbar vom Benutzer stammten.
ACL-Verlust durch Typverwirrung (CVE-2005-2801)
Produkt verglich nicht alle erforderlichen Daten in separaten Elementen, behandelte sie fälschlicherweise als identisch und verursachte Verlust von Zugriffskontrolllisten.
Tools zum Testen/Ausnutzen
-
Burp Suite — Testen auf Typverwirrung in Webanwendungen.
-
Browser DevTools — Ereignisbehandlung und Typprüfung testen.
-
file-Befehl — Tatsächliche Dateitypen vs Erweiterungen analysieren.
CVE-Beispiele
-
CVE-2005-2260 — Browser-Ereignistyp-Verwirrung.
-
CVE-2005-2801 — Unvollständiger Elementvergleich führt zu ACL-Verlust.
Referenzen
-
MITRE Corporation. "CWE-351: Insufficient Type Distinction." Common Weakness Enumeration. https://cwe.mitre.org/data/definitions/351.html
-
MDN Web Docs. "Event.isTrusted." https://developer.mozilla.org/en-US/docs/Web/API/Event/isTrusted
-
OWASP Foundation. "Input Validation Cheat Sheet." https://cheatsheetseries.owasp.org/cheatsheets/Input_Validation_Cheat_Sheet.html