Artikel

Was ist eine IDOR-Schwachstelle? Authentication vs. Authorization und wie du BOLA verhinderst

Wenn du in der URL /invoices/1042 zu /invoices/1043 änderst und damit die private Rechnung eines anderen Kunden siehst, hat dein Backend eine IDOR-Schwachstelle (Broken Object Level Authorization) – die Nummer 1 der OWASP API Security Top 10.

Furkan Özay24. Oktober 2026 · 3 Min. Lesezeit
czCZAY.DEV // EDITORIALDE
GÜVENLIK

#Güvenlik · 3 MIN LESEZEIT

FURKAN ÖZAYVOL. 2026 // #C61D

Stell dir vor, du loggst dich in eine E-Commerce-Plattform ein, öffnest deine letzte Rechnung unter https://example.com/api/invoices/1042, dann änderst du aus Neugier die URL in der Adressleiste auf 1043.

Wenn der Server dann den vollständigen Namen, die Wohnadresse und die Steuernummer eines anderen Kunden zurückgibt, hat dieses System eine katastrophale IDOR-Schwachstelle (Insecure Direct Object Reference) – von OWASP als API1: Broken Object Level Authorization (BOLA) eingestuft, die häufigste und gefährlichste Schwachstelle in modernen APIs.

· · ·

1. Warum entsteht IDOR? Authentication und Authorization werden verwechselt

Fast jeder Backend-Entwickler denkt daran, geschützten Routen eine Authentication-Middleware (requireAuth oder verifyJWT) vorzuschalten. Authentication und Authorization beantworten aber zwei völlig verschiedene Fragen:

  • Authentication (401 Unauthorized): „Wer bist du? Bist du in einem gültigen Konto angemeldet?“
  • Authorization (403 Forbidden): „Gehört dir Ressource #1043 tatsächlich, oder darfst du darauf zugreifen?“

Das verwundbare Code-Muster

typescript
// ❌ VULNERABLE: Checks if the user is logged in, but never checks ownership!
app.get('/api/invoices/:id', requireAuth, async (req, res) => {
  const invoice = await db.invoices.findUnique({
    where: { id: Number(req.params.id) }
  });
  return res.json(invoice);
});

Weil der Angreifer in seinem eigenen, gültigen Konto angemeldet ist, geht requireAuth durch! Mit einem Skript von fünf Zeilen kann er dann von 1 bis 500.000 durchzählen und deine gesamte Datenbank in wenigen Minuten abgreifen.

· · ·

2. Der UUID-Mythos: „Ich nutze UUIDv4, also bin ich sicher!“

Warnung: Security by Obscurity ist KEINE Sicherheit

Wenn du fortlaufende Integer (1042) durch zufällige UUIDs (f47ac10b-58cc-4372-a567-0e02b2c3d479) ersetzt, wird Brute-Force-Raten schwerer, aber die IDOR-Schwachstelle ist damit nicht behoben! Objekt-IDs tauchen oft in öffentlichen Profilen, Webhook-Payloads, im Browserverlauf oder in GraphQL-Antworten auf. Wenn der Besitz nicht geprüft wird, kann jeder, der die UUID in die Hände bekommt, den Datensatz weiterhin lesen oder löschen.

· · ·

3. Die echte Lösung: Besitz auf Ebene der Datenbankabfrage erzwingen

Vertraue niemals einer ID aus req.params oder req.body für sich allein. Binde die Abfrage immer direkt an die Identität aus der Session bzw. dem JWT des authentifizierten Nutzers (req.user.id):

typescript
// ✅ SECURE: Combines object ID with the authenticated user's ID in the WHERE clause
app.get('/api/invoices/:id', requireAuth, async (req, res) => {
  const invoice = await db.invoices.findFirst({
    where: {
      id: req.params.id,
      userId: req.user.id // <- Strict Object-Level Authorization!
    }
  });
 
  if (!invoice) {
    // Return 404 (or 403) so attackers cannot even probe if the ID exists
    return res.status(404).json({ error: 'Invoice not found' });
  }
 
  return res.json(invoice);
});

Wenn du PostgreSQL einsetzt, kannst du noch einen Schritt weitergehen und Row-Level Security (RLS) auf Ebene der Datenbank-Engine erzwingen, sodass eine Abfrage mathematisch gar keine Zeilen eines anderen Mandanten (Tenants) zurückgeben kann.

Interaktive Roadmap & Tool

Als Nächstes lesen