427 lines
17 KiB
YAML
427 lines
17 KiB
YAML
lessonKey: "idor-demo"
|
|
title: "IDOR - Unsichere direkte Objektreferenz"
|
|
description: "Erfahre, wie unsichere direkte Objektreferenzen durch URL-Manipulation den unbefugten Zugriff auf Daten anderer Benutzer ermöglichen"
|
|
difficultyLevel: "intermediate"
|
|
estimatedDuration: 22
|
|
module: "idor-demo"
|
|
|
|
steps:
|
|
- id: "intro"
|
|
type: "content"
|
|
title: "Was ist IDOR?"
|
|
content: |
|
|
IDOR (Insecure Direct Object Reference - Unsichere direkte Objektreferenz) ist eine Sicherheitslücke, die auftritt, wenn eine Anwendung direkten Zugriff auf Objekte basierend auf vom Benutzer bereitgestellten Eingaben ermöglicht. Wenn die Anwendung nicht ordnungsgemäß überprüft, ob der Benutzer berechtigt ist, auf das angeforderte Objekt zuzugreifen, können Angreifer auf unbefugte Daten zugreifen.
|
|
|
|
**Wie IDOR funktioniert:**
|
|
|
|
Eine anfällige URL könnte so aussehen:
|
|
https://bank.com/profile?userId=123
|
|
|
|
Wenn die Anwendung nicht prüft, ob der angemeldete Benutzer auf die Daten von Benutzer 123 zugreifen darf, kann ein Angreifer einfach den Parameter ändern:
|
|
https://bank.com/profile?userId=124 ← Zugriff auf die Daten eines anderen Benutzers!
|
|
|
|
**IDOR in den OWASP Top 10:**
|
|
IDOR fällt unter **A01:2021 - Fehlerhafte Zugriffskontrolle**, das kritischste Sicherheitsrisiko für Webanwendungen.
|
|
|
|
**Häufige IDOR-Ziele:**
|
|
• Benutzerprofile und Kontodaten
|
|
• Private Nachrichten und E-Mails
|
|
• Finanzdaten und Transaktionen
|
|
• Medizinische Aufzeichnungen
|
|
• Bestellhistorien
|
|
• Private Dateien und Dokumente
|
|
• Verwaltungsfunktionen
|
|
|
|
**Warum es gefährlich ist:**
|
|
• Einfach auszunutzen (nur einen URL-Parameter ändern)
|
|
• Bleibt oft unentdeckt
|
|
• Kann sensible persönliche Daten offenlegen
|
|
• Kann Datenschutzgesetze verletzen (DSGVO, HIPAA, etc.)
|
|
• Kann zu Identitätsdiebstahl führen
|
|
• Keine speziellen Werkzeuge erforderlich
|
|
|
|
- id: "auth-vs-authz"
|
|
type: "content"
|
|
title: "Authentifizierung vs. Autorisierung"
|
|
content: |
|
|
Das Verständnis des Unterschieds zwischen Authentifizierung und Autorisierung ist entscheidend zur Verhinderung von IDOR:
|
|
|
|
**Authentifizierung (AuthN):**
|
|
"Wer bist du?"
|
|
|
|
• Verifiziert die Benutzeridentität
|
|
• Verwendet Anmeldedaten (Benutzername/Passwort, Tokens, etc.)
|
|
• Bestätigt, dass du die Person bist, für die du dich ausgibst
|
|
• Beispiel: Anmeldung in deinem Konto
|
|
|
|
**Autorisierung (AuthZ):**
|
|
"Was darfst du tun?"
|
|
|
|
• Verifiziert Benutzerberechtigungen
|
|
• Prüft, ob du auf bestimmte Ressourcen zugreifen kannst
|
|
• Bestimmt, was du sehen oder ändern kannst
|
|
• Beispiel: Überprüfung, ob du ein bestimmtes Profil ansehen darfst
|
|
|
|
**Das IDOR-Problem:**
|
|
|
|
Viele Anwendungen implementieren Authentifizierung, vergessen aber die Autorisierung!
|
|
|
|
✅ Benutzer ist authentifiziert (angemeldet)
|
|
❌ Anwendung prüft nicht, ob der Benutzer auf diese spezifische Ressource zugreifen darf
|
|
= IDOR-Sicherheitslücke
|
|
|
|
**Analogie aus der realen Welt:**
|
|
|
|
Authentifizierung = Einen Schlüssel zum Betreten des Gebäudes haben
|
|
Autorisierung = Die Erlaubnis haben, bestimmte Räume zu betreten
|
|
|
|
Bei IDOR hast du einen Schlüssel zum Gebäude (du bist angemeldet), aber die Anwendung prüft nicht, welche Räume du betreten darfst. Du kannst jede Tür öffnen, indem du verschiedene Raumnummern ausprobierst!
|
|
|
|
**Beispielszenarien:**
|
|
|
|
**Szenario 1: Soziale Medien**
|
|
• Du bist angemeldet (authentifiziert ✅)
|
|
• Du versuchst, eine Nachricht anzusehen: /messages/12345
|
|
• App prüft nicht, ob Nachricht 12345 dir gehört (keine Autorisierung ❌)
|
|
• Du kannst private Nachrichten von jedem lesen, indem du die ID änderst
|
|
|
|
**Szenario 2: E-Commerce**
|
|
• Du bist angemeldet (authentifiziert ✅)
|
|
• Du siehst deine Bestellung: /orders/5001
|
|
• App überprüft nicht den Bestellbesitz (keine Autorisierung ❌)
|
|
• Du kannst die Bestellungen, Adressen und Kaufhistorie von jedem sehen
|
|
|
|
**Szenario 3: Gesundheitswesen**
|
|
• Du bist als Patient angemeldet (authentifiziert ✅)
|
|
• Du siehst Laborergebnisse: /results/patient/789
|
|
• App prüft nicht, ob du Patient 789 bist (keine Autorisierung ❌)
|
|
• Du kannst auf medizinische Aufzeichnungen von jedem zugreifen, indem du die ID änderst
|
|
|
|
- id: "idor-demo"
|
|
type: "interactive"
|
|
title: "IDOR-Sicherheitslücken-Demo"
|
|
interactiveComponent: "IDORDemo"
|
|
content: |
|
|
Unten ist eine simulierte Online-Banking-Anwendung mit einer IDOR-Sicherheitslücke. Du bist als "Max Mustermann" (Benutzer-ID 55) angemeldet.
|
|
|
|
Die Anwendung verwendet einen URL-Parameter zum Abrufen von Benutzerprofilen:
|
|
|
|
`https://securebank.example/profile?ref=dashboard&userId=55`
|
|
|
|
**Deine Aufgabe:**
|
|
|
|
1. Untersuche die URL-Struktur und identifiziere den anfälligen Parameter
|
|
|
|
2. Versuche, den userId-Parameter zu ändern, um auf andere Benutzer zuzugreifen
|
|
|
|
3. Beobachte, wie du auf private Informationen zugreifen kannst, die du nicht sehen solltest
|
|
|
|
4. Finde versteckte Benutzer durch systematisches Testen verschiedener IDs
|
|
|
|
5. Du hast 5 Minuten Zeit - versuche so viele Benutzer wie möglich zu entdecken!
|
|
|
|
**Hinweise:**
|
|
|
|
- Nicht alle IDs existieren - manche Benutzer wurden gelöscht
|
|
|
|
- Es gibt besondere Belohnungen für bestimmte Entdeckungen
|
|
|
|
- Achte auf die Entdeckungsanzeige oben
|
|
|
|
Dies demonstriert, warum Anwendungen Autorisierung überprüfen müssen, nicht nur Authentifizierung.
|
|
|
|
- id: "question-1"
|
|
type: "question"
|
|
questionType: "multiple_choice"
|
|
question: "Welche der folgenden URL-Muster deuten auf potenzielle IDOR-Sicherheitslücken hin?"
|
|
options:
|
|
- id: "user-id-param"
|
|
text: "/api/user?id=123"
|
|
isCorrect: true
|
|
points: 10
|
|
- id: "order-id-param"
|
|
text: "/orders/view?orderId=5001"
|
|
isCorrect: true
|
|
points: 10
|
|
- id: "document-id-param"
|
|
text: "/documents/download/42"
|
|
isCorrect: true
|
|
points: 10
|
|
- id: "session-token"
|
|
text: "/profile (verwendet Session-Token im Header)"
|
|
isCorrect: false
|
|
points: 0
|
|
- id: "message-id-param"
|
|
text: "/messages/inbox/msg_789"
|
|
isCorrect: true
|
|
points: 10
|
|
maxPoints: 40
|
|
feedback:
|
|
correct: "Ausgezeichnet! All diese Muster mit direkten Objekt-IDs in URLs oder Parametern sind potenzielle IDOR-Ziele, wenn keine ordnungsgemäße Autorisierung implementiert ist."
|
|
partial: "Gut! Du hast einige IDOR-Muster erkannt. Jede URL, die Ressourcen-IDs (Benutzer, Bestellungen, Dokumente, Nachrichten) enthält, benötigt Autorisierungsprüfungen."
|
|
incorrect: "Suche nach URLs, die identifizierbare Ressourcen-IDs (Zahlen oder Kennungen) enthalten. Diese benötigen alle eine ordnungsgemäße Autorisierung, um IDOR zu verhindern. Session-Tokens sind sicher, weil sie serverseitig verifiziert werden."
|
|
|
|
- id: "real-world-impact"
|
|
type: "content"
|
|
title: "IDOR-Datenlecks in der realen Welt"
|
|
content: |
|
|
IDOR-Sicherheitslücken haben zu massiven Datenlecks und Datenschutzverletzungen geführt:
|
|
|
|
**Facebook (2019) - 419 Millionen Datensätze**
|
|
• Telefonnummern durch IDOR offengelegt
|
|
• Angreifer konnten Benutzer-IDs aufzählen
|
|
• Datenbank enthielt Facebook-IDs und Telefonnummern
|
|
• Betraf Benutzer weltweit
|
|
• Führte zu erheblichen Datenschutzbedenken
|
|
|
|
**Bumble Dating App (2019)**
|
|
• IDOR ermöglichte Zugriff auf jedes Benutzerprofil
|
|
• Angreifer konnten private Fotos ansehen
|
|
• Konnte auf als "versteckt" markierte Benutzer zugreifen
|
|
• Echtzeit-Standortdaten offengelegt
|
|
• Profile von 95 Millionen Benutzern erfasst
|
|
|
|
**Parler Social Network (2021)**
|
|
• IDOR in Post- und Benutzer-APIs
|
|
• Alle Beiträge waren sequentiell nummeriert
|
|
• Angreifer erfassten 70TB Daten
|
|
• Enthielt gelöschte Beiträge und Metadaten
|
|
• Enthielt GPS-Koordinaten aus Videos
|
|
|
|
**Verizon (2017)**
|
|
• IDOR legte 14 Millionen Kundendatensätze offen
|
|
• Kontodetails, Telefonnummern und PINs
|
|
• Einfache Parametermanipulation
|
|
• Ohne Authentifizierung zugänglich
|
|
• Benötigte 6 Monate zur Entdeckung
|
|
|
|
**USPS Informed Visibility (2018)**
|
|
• IDOR legte 60 Millionen Benutzer offen
|
|
• E-Mail-Adressen, Telefonnummern und Adressen
|
|
• Mailingkampagnendaten
|
|
• Kontodetails und Präferenzen
|
|
• Wildcard-Suchsicherheitslücke
|
|
|
|
**PizzaHut Australia (2020)**
|
|
• IDOR in Bestell-API
|
|
• Kundennamen, Adressen und Bestellhistorie
|
|
• Kreditkartendetails (teilweise)
|
|
• Lieferanweisungen
|
|
• Telefonnummern
|
|
|
|
**Auswirkungsstatistiken:**
|
|
• IDOR erscheint in ~15% aller Webanwendungen
|
|
• Durchschnittliche Kosten eines IDOR-Lecks: 3,86 Millionen Dollar
|
|
• Durchschnittliche Zeit zur Entdeckung: 197 Tage
|
|
• Durchschnittliche Zeit zur Eindämmung: 69 Tage
|
|
• 60% der Organisationen erlebten IDOR in den letzten 2 Jahren
|
|
|
|
**Rechtliche Konsequenzen:**
|
|
• DSGVO-Strafen bis zu 20 Millionen Euro oder 4% des Umsatzes
|
|
• CCPA-Strafen bis zu 7.500 Dollar pro Verstoß
|
|
• Sammelklagen von betroffenen Benutzern
|
|
• Verlust von Kundenvertrauen und Reputation
|
|
• Behördliche Untersuchungen
|
|
• Verpflichtende Benachrichtigungen über Datenlecks
|
|
|
|
- id: "question-2"
|
|
type: "question"
|
|
questionType: "single_choice"
|
|
question: "Was ist der BESTE Weg, um IDOR-Sicherheitslücken zu verhindern?"
|
|
options:
|
|
- id: "hide-ids"
|
|
text: "Alle Objekt-IDs in URLs verstecken oder verschlüsseln"
|
|
isCorrect: false
|
|
points: 0
|
|
- id: "session-check"
|
|
text: "Überprüfen, dass der authentifizierte Benutzer die Berechtigung hat, auf die angeforderte Ressource zuzugreifen"
|
|
isCorrect: true
|
|
points: 30
|
|
- id: "rate-limiting"
|
|
text: "Rate-Limiting implementieren, um ID-Aufzählung zu verhindern"
|
|
isCorrect: false
|
|
points: 0
|
|
- id: "complex-ids"
|
|
text: "Komplexe, zufällige IDs anstelle von sequentiellen Nummern verwenden"
|
|
isCorrect: false
|
|
points: 0
|
|
maxPoints: 30
|
|
feedback:
|
|
correct: "Perfekt! Ordnungsgemäße Autorisierungsprüfungen sind unerlässlich. Jede Anfrage muss überprüfen, ob der Benutzer die Berechtigung hat, auf die spezifische Ressource zuzugreifen, unabhängig davon, wie die ID formatiert ist."
|
|
incorrect: "Obwohl Verschleierung und Rate-Limiting helfen können, lösen sie nicht das Grundproblem. Die Anwendung MUSS überprüfen, dass der authentifizierte Benutzer die Autorisierung hat, auf jede spezifische Ressource zuzugreifen, bevor sie zurückgegeben wird."
|
|
|
|
- id: "secure-design"
|
|
type: "content"
|
|
title: "Sichere Designmuster"
|
|
content: |
|
|
**IDOR verhindern: Best Practices**
|
|
|
|
**1. Zugriffskontrollprüfungen implementieren**
|
|
|
|
Jeder Ressourcenzugriff muss die Autorisierung überprüfen:
|
|
|
|
// ❌ ANFÄLLIG - Keine Autorisierungsprüfung
|
|
app.get('/api/profile/:userId', authenticate, (req, res) => {
|
|
const user = db.getUserById(req.params.userId);
|
|
res.json(user); // Gibt die Daten eines beliebigen Benutzers zurück!
|
|
});
|
|
|
|
// ✅ SICHER - Ordnungsgemäße Autorisierung
|
|
app.get('/api/profile/:userId', authenticate, (req, res) => {
|
|
const requestedUserId = req.params.userId;
|
|
const currentUserId = req.session.userId;
|
|
|
|
// Prüfen, ob Benutzer Berechtigung hat
|
|
if (requestedUserId !== currentUserId && !req.session.isAdmin) {
|
|
return res.status(403).json({ error: 'Forbidden' });
|
|
}
|
|
|
|
const user = db.getUserById(requestedUserId);
|
|
res.json(user);
|
|
});
|
|
|
|
**2. Indirekte Referenzen verwenden**
|
|
|
|
Datenbank-IDs nicht direkt offenlegen:
|
|
|
|
// ❌ Direkte Referenz auf Datenbank-ID
|
|
GET /api/messages/12345
|
|
|
|
// ✅ Indirekte Referenz durch Benutzerkontext
|
|
GET /api/messages/inbox (gibt nur Nachrichten des Benutzers zurück)
|
|
GET /api/messages/sent (gibt nur gesendete Nachrichten des Benutzers zurück)
|
|
|
|
// Wenn du IDs verwenden musst, überprüfe den Besitz:
|
|
GET /api/messages/msg_abc123
|
|
// Dann prüfen: db.isMessageOwnedBy(msg_abc123, currentUserId)
|
|
|
|
**3. Rollenbasierte Zugriffskontrolle (RBAC) implementieren**
|
|
|
|
Klare Berechtigungsmodelle definieren:
|
|
|
|
const permissions = {
|
|
user: {
|
|
canViewOwnProfile: true,
|
|
canViewOtherProfiles: false,
|
|
canEditOwnProfile: true,
|
|
canEditOtherProfiles: false
|
|
},
|
|
admin: {
|
|
canViewOwnProfile: true,
|
|
canViewOtherProfiles: true,
|
|
canEditOwnProfile: true,
|
|
canEditOtherProfiles: true
|
|
}
|
|
};
|
|
|
|
function checkPermission(user, action, resource) {
|
|
if (action === 'view' && resource.ownerId !== user.id) {
|
|
return permissions[user.role].canViewOtherProfiles;
|
|
}
|
|
return permissions[user.role][`can${action}`];
|
|
}
|
|
|
|
**4. Sitzungsbasierten Ressourcenzugriff verwenden**
|
|
|
|
Lass die Sitzung bestimmen, auf welche Ressourcen zugegriffen werden kann:
|
|
|
|
// ✅ Aktuelle Benutzerdaten aus Sitzung abrufen
|
|
app.get('/api/profile', authenticate, (req, res) => {
|
|
const userId = req.session.userId; // Aus verifizierter Sitzung
|
|
const user = db.getUserById(userId);
|
|
res.json(user);
|
|
});
|
|
|
|
// ✅ Bestellungen des aktuellen Benutzers aus Sitzung abrufen
|
|
app.get('/api/orders', authenticate, (req, res) => {
|
|
const userId = req.session.userId;
|
|
const orders = db.getOrdersByUserId(userId);
|
|
res.json(orders);
|
|
});
|
|
|
|
**5. Zugriffskontrolllisten (ACLs) implementieren**
|
|
|
|
Für komplexe Berechtigungen:
|
|
|
|
class AccessControl {
|
|
canAccess(userId, resourceType, resourceId) {
|
|
// Besitz prüfen
|
|
const resource = db.getResource(resourceType, resourceId);
|
|
if (resource.ownerId === userId) return true;
|
|
|
|
// Freigabeberechtigungen prüfen
|
|
const acl = db.getACL(resourceType, resourceId);
|
|
if (acl.sharedWith.includes(userId)) return true;
|
|
|
|
// Gruppenberechtigungen prüfen
|
|
const user = db.getUser(userId);
|
|
if (acl.groupsWithAccess.some(g => user.groups.includes(g))) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
**6. Zugriffsversuche protokollieren und überwachen**
|
|
|
|
app.get('/api/resource/:id', authenticate, (req, res) => {
|
|
const resourceId = req.params.id;
|
|
const userId = req.session.userId;
|
|
|
|
// Zugriffsversuch protokollieren
|
|
logger.info('Ressourcenzugriffsversuch', {
|
|
userId,
|
|
resourceId,
|
|
timestamp: Date.now()
|
|
});
|
|
|
|
// Autorisierung prüfen
|
|
if (!canAccess(userId, 'resource', resourceId)) {
|
|
// Unbefugten Versuch protokollieren
|
|
logger.warn('Unbefugter Zugriffsversuch', {
|
|
userId,
|
|
resourceId,
|
|
ip: req.ip
|
|
});
|
|
|
|
// Sicherheitsteam bei mehreren Versuchen benachrichtigen
|
|
securityMonitor.recordUnauthorizedAccess(userId, resourceId);
|
|
|
|
return res.status(403).json({ error: 'Forbidden' });
|
|
}
|
|
|
|
// Mit autorisiertem Zugriff fortfahren
|
|
const resource = db.getResource(resourceId);
|
|
res.json(resource);
|
|
});
|
|
|
|
**7. Auf IDOR testen**
|
|
|
|
**Manuelles Testen:**
|
|
1. Als Benutzer A anmelden
|
|
2. Auf eine Ressource zugreifen: `/api/profile/123`
|
|
3. Die ID in der URL/dem Parameter notieren
|
|
4. Auf eine andere ID ändern: `/api/profile/124`
|
|
5. Wenn du auf die Daten von Benutzer B zugreifen kannst → IDOR-Sicherheitslücke!
|
|
|
|
**Automatisiertes Testen:**
|
|
• Tools wie Burp Suite, OWASP ZAP verwenden
|
|
• Alle Endpunkte mit verschiedenen Benutzerrollen testen
|
|
• IDs aufzählen, um zugängliche Ressourcen zu finden
|
|
• Auf horizontale Rechteausweitung prüfen (gleiche Rolle, anderer Benutzer)
|
|
• Auf vertikale Rechteausweitung prüfen (andere Rolle)
|
|
|
|
**Sicherheits-Checkliste:**
|
|
✅ Alle Ressourcenzugriffe haben Autorisierungsprüfungen
|
|
✅ Datenbank-IDs werden wenn möglich nicht direkt offengelegt
|
|
✅ Rollenbasierte Zugriffskontrolle ist implementiert
|
|
✅ Zugriffsversuche werden protokolliert und überwacht
|
|
✅ Sensible Operationen erfordern zusätzliche Verifizierung
|
|
✅ Regelmäßige Sicherheitsaudits und Penetrationstests
|
|
✅ Entwicklerschulung zur IDOR-Prävention
|
|
|
|
scoring:
|
|
passingScore: 105
|
|
maxTotalPoints: 210 # 70 from questions + up to 140 from interactive discoveries
|