Broken Object-Level Authorization (BOLA / IDOR): der API-Fehler, den wir am häufigsten finden
Eine BOLA-Schwachstelle (auch IDOR genannt) ist der Fehler, den wir bei API-Tests am häufigsten melden. So spüren wir sie auf, indem wir Objekt-IDs über zwei Konten hinweg austauschen, und so schließen Sie sie mit serverseitiger Autorisierung.

Ändern Sie eine Zahl in einer URL, und schon lesen Sie die Rechnung eines anderen. Genau das ist der ganze Trick hinter einer BOLA-Schwachstelle, und es ist der Befund, den wir bei API-Projekten häufiger dokumentieren als jeden anderen. Der Endpunkt verhält sich für den angemeldeten Nutzer tadellos. Er liefert sauberes JSON, besteht jeden Funktionstest und gibt dann klammheimlich jeden Datensatz heraus, nach dem Sie fragen, solange Sie die ID kennen.
Broken Object-Level Authorization (BOLA) ist der Name der API-Ära für das, was die meisten Entwickler noch immer IDOR nennen, eine Insecure Direct Object Reference. Sie steht als API1:2023 an der Spitze der OWASP API Security Top 10, und dieser Platz ist verdient. Sie lässt sich leicht ausliefern, übersteht das Code-Review und bleibt für einen Scanner, der keine Ahnung von Ihrem Datenmodell hat, unsichtbar. Über die REST- und GraphQL-Backends hinweg, die wir testen, sorgt allein diese Klasse für einen großen Anteil unserer Befunde mit hohem und kritischem Schweregrad.
Der Vorteil: Eine BOLA-Schwachstelle gehört zugleich zu den am besten vermeidbaren Fehlern der Liste, sobald Sie ihr Muster kennen. Dieser Beitrag zeigt, was sie ist, wie wir sie in einem echten Projekt aufspüren, wie die rohe Anfrage und Antwort aussehen, welchen Schaden sie in der Produktion anrichtet und welche Gegenmaßnahme wirklich standhält.
Die wichtigsten Erkenntnisse
- Eine BOLA-Schwachstelle (auch IDOR genannt) entsteht, wenn eine API ein Objekt anhand einer vom Client gelieferten ID zurückgibt oder verändert, ohne zu prüfen, ob der Aufrufer überhaupt auf dieses Objekt zugreifen darf.
- Sie ist OWASP API1:2023 (Broken Object Level Authorization) und entspricht CWE-639, Authorization Bypass Through User-Controlled Key.
- Wir finden sie, indem wir uns mit zwei getrennten Konten authentifizieren und die Anfragen von Konto A mit dem Token von Konto B wiederholen, dabei Objekt-IDs austauschen und auf 200er-Antworten achten, die die Daten des falschen Nutzers preisgeben.
- Fortlaufende Ganzzahl-IDs machen die massenhafte Enumeration trivial, doch UUIDs und Hashes beheben den Fehler nicht. Sie verlangsamen das Raten nur.
- Die einzige verlässliche Gegenmaßnahme ist eine serverseitige Autorisierungsprüfung für jedes Objekt, bei jeder Anfrage, gebunden an die authentifizierte Sitzung statt an irgendeine ID, die der Client sendet.
Was ist eine BOLA-Schwachstelle (und worin unterscheidet sie sich von IDOR)?
Eine BOLA-Schwachstelle ist das Versäumnis zu bestätigen, dass der authentifizierte Aufrufer auf genau das Objekt zugreifen darf, nach dem er gefragt hat. Die API authentifiziert Sie einwandfrei. Sie weiß genau, wer Sie sind. Dann übernimmt sie eine Objekt-ID direkt aus der Anfrage und überspringt die einzige Frage, auf die es ankommt: Gehört dieses Objekt Ihnen?
IDOR und BOLA beschreiben dieselbe Grundursache. IDOR ist der ältere, breiter gefasste Web-Begriff. BOLA ist der Name, den OWASP für die Variante auf Objektebene gewählt hat, als es die API Security Top 10 aufstellte, denn APIs legen Objektbezeichner überall offen, und das Muster wurde zum vorherrschenden API-Risiko. Wenn wir in einem Bericht “IDOR” schreiben, meinen wir genau das: Die Objektreferenz ist direkt, vom Nutzer steuerbar und ungeschützt. In diesem Artikel verwenden wir beide Begriffe für denselben Befund.
Es hilft, BOLA von seinem Verwandten abzugrenzen, der Broken Function Level Authorization (API5:2023). Bei Fehlern auf Funktionsebene geht es darum, eine Aktion aufzurufen, die Sie überhaupt nicht aufrufen dürften, etwa eine Route, die nur Administratoren offensteht. Bei Fehlern auf Objektebene geht es darum, einen völlig legitimen Endpunkt auf Daten aufzurufen, die nicht Ihnen gehören. Sie können jede Route abgeriegelt haben und trotzdem jeden Kundendatensatz über einen einzigen ungeprüften id-Parameter verlieren.
Warum sind REST- und GraphQL-APIs so anfällig dafür?
APIs sind anfällig für BOLA, weil sie um adressierbare Objekte herum aufgebaut sind, und jedes einzelne dieser Objekte braucht seinen eigenen Wächter. Eine klassische, serverseitig gerenderte Anwendung schränkt Daten oft eher zufällig auf die Sitzung ein. Die Seite fragt ohnehin nur “meine” Bestellungen ab, es gibt also nichts, was sich über eine beliebige ID abrufen ließe. Eine API macht das Gegenteil. Sie veröffentlicht eine einheitliche Oberfläche wie /api/orders/{id} und lädt den Client dazu ein, das Objekt direkt zu benennen. Multiplizieren Sie das mit ein paar hundert Endpunkten und ein paar Dutzend Objekttypen, und die Wahrscheinlichkeit, dass einer davon seine Eigentumsprüfung vergessen hat, steigt rasch.
REST legt den Bezeichner ganz offen dar. Er steht im Pfad oder in einem Query-String, ist oft eine fortlaufende Ganzzahl und lässt sich in etwa zehn Sekunden fuzzen. GraphQL versteckt dasselbe Problem an einer anderen Stelle. Ein einziger Endpunkt akzeptiert ein id-Argument an verschachtelten Resolvern, und die Autorisierung muss auf Feld- und Knotenebene durchgesetzt werden. Entwickler, die die oberste Query absichern, übersehen regelmäßig die verschachtelten node(id: ...)-Abfragen, gebündelte Aliase oder Connection-Edges, die Objekte auf eigene Faust auflösen. Das Ergebnis ist identisch: Übergeben Sie eine ID, die Ihnen nicht gehört, und Sie erhalten Daten, die Sie nicht sehen dürften.
Microservices setzen noch einen weiteren Fehlermodus obendrauf. Sobald eine Anfrage eine interne Vertrauensgrenze überschreitet, gehen nachgelagerte Dienste gern davon aus, dass das Gateway die Autorisierung bereits erledigt hat, und lösen daher bereitwillig jede Objekt-ID auf, die bei ihnen landet.
Wie spüren wir eine BOLA-Schwachstelle bei einem Projekt auf?
Unsere Methode ist bewusst langweilig: sich mit zwei getrennten Konten mit geringen Rechten authentifizieren und dann versuchen, ein Konto auf die Daten des anderen zugreifen zu lassen. Langweilig ist genau das, was zuverlässig echte Fehler findet. So läuft der Kreislauf ab.
Zuerst kartieren wir die Objektoberfläche. Wir leiten die Anwendung über Burp Suite um, klicken uns als Nutzer A durch jede Funktion und katalogisieren jeden Endpunkt, der einen Objektbezeichner annimmt. Bestell-IDs, Dokument-IDs, Nachrichten-Threads, Rechnungsnummern, Profilnamen, Datei-Schlüssel. Alles, was der Client benennen darf, kommt auf die Liste.
Als Nächstes charakterisieren wir die Bezeichner. Fortlaufende Ganzzahlen bedeuten, dass ein Angreifer den gesamten Datenbestand durchlaufen kann, indem er von 1 aufwärts zählt. UUIDs, ULIDs und Hashes erhöhen den Aufwand, und wir behandeln sie als Bremsschwelle, nicht als Kontrolle. Immer wieder stellen wir fest, dass “nicht erratbare” IDs über irgendeinen anderen Kanal durchsickern: eine Listenansicht, eine E-Mail-Bestätigung, einen Empfehlungslink, eine GraphQL-Edge, einen Stack-Trace in einer Fehlerantwort. Sobald die ID irgendwo offenliegt, spielt ihre Entropie keine Rolle mehr.
Dann kommt der Kontowechsel mit zwei Konten. Wir erfassen die Anfragen von Nutzer A und wiederholen sie mit dem Sitzungs-Token von Nutzer B, wobei wir nur die Objekt-ID ändern, sodass sie wieder auf die Ressource von A zeigt. Genau hier verdient sich die Autorize-Erweiterung für Burp ihren Platz in der Werkzeugleiste. Geben Sie ihr das Cookie oder Bearer-Token von Nutzer B, und sie wiederholt still jede Anfrage, die Sie stellen, als B und markiert die Antworten anschließend grün (durchgesetzt), rot (umgangen) oder orange, wenn sie sich nicht entscheiden kann und einen Menschen zum Nachsehen braucht. Eine rote Zeile mit den Daten von A in der Antwort von B ist eine BOLA-Schwachstelle, Punkt.
Wir halten nie bei GET an. Einige der hässlichsten Befunde, die wir abliefern, betreffen PUT, PATCH und DELETE, wo eine fehlende Prüfung es einem Nutzer erlaubt, die Datensätze eines anderen zu überschreiben oder zu zerstören. Wir verschieben den Bezeichner auch: Eine ID, die in der URL geprüft wird, wird manchmal ignoriert, wenn derselbe Wert in einen JSON-Body gelegt wird, und ein Mass-Assignment-Feld wie "userId" kann das Objekt klammheimlich jemand anderem zuordnen. Für die Enumeration in großem Maßstab treiben wir den ID-Parameter mit ffuf oder Burp Intruder an und vergleichen Statuscodes und Antwortlängen, um zu erkennen, welche IDs echte Daten zurückliefern und welche ein einheitliches 404.
Wie sieht die verwundbare Anfrage tatsächlich aus?
Hier ist ein anonymisiertes Beispiel gegen ein fiktives Ziel. Nutzer B ist mit seinem eigenen gültigen Token authentifiziert, fragt aber Bestellung 1024 ab, die Nutzer A gehört.
GET /api/orders/1024 HTTP/1.1
Host: api.example.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.userB-token
Accept: application/json
Eine sichere API antwortet mit 404 Not Found oder 403 Forbidden, weil Bestellung 1024 nicht dem Nutzer B zugeordnet ist. Eine verwundbare authentifiziert das Token, sucht die Bestellung allein anhand der ID heraus und serialisiert sie direkt zurück:
HTTP/1.1 200 OK
Content-Type: application/json
{
"orderId": 1024,
"customer": "Alice Nguyen",
"email": "[email protected]",
"shippingAddress": "742 Evergreen Terrace",
"items": [ { "sku": "SKU-88213", "qty": 2 } ],
"total": "184.00",
"paymentLast4": "4242"
}
Das Token gehört Nutzer B. Die Daten gehören Nutzer A. An der Antwort ist nichts fehlerhaft. Der Server hat genau das getan, was der Code ihm aufgetragen hat, nämlich Bestellung 1024 abzurufen und zurückzugeben. Tauschen Sie 1024 gegen 1025, dann 1026, und schon haben Sie sich per Skript durch die gesamte Bestelltabelle gearbeitet. Das ist der Fehler in seiner reinsten Form.
Wie sehen die Auswirkungen in der Praxis aus?
Die Auswirkung ist eine massenhafte Datenpreisgabe, obendrein oft eine Kontoübernahme. Weil sich die Enumeration per Skript automatisieren lässt, gibt ein einziger ungeschützter Endpunkt nicht nur einen Datensatz preis. Er gibt sie alle preis. Wir haben erlebt, wie Fehler auf Objektebene vollständige Kunden-PII, Bestellhistorien, Zahlungsmetadaten, private Nachrichten und interne Dokumente offengelegt haben, alles erreichbar über eine Schleife, die sich durch die IDs zählt, während Sie sich einen Kaffee holen.
Selten bleibt es beim Lesen. Wenn dasselbe Muster auf einem Profil- oder Einstellungs-Endpunkt sitzt, der PATCH akzeptiert, kann ein Angreifer die E-Mail-Adresse oder Telefonnummer eines anderen Nutzers ändern, dann ein Zurücksetzen des Passworts an die nun von ihm kontrollierte Adresse auslösen, und aus dem Lesefehler wird eine vollständige Kontoübernahme. Handelt es sich beim Objekt um einen API-Schlüssel, ein Webhook-Secret oder ein Einladungs-Token, wird aus dem Leck ein Sprungbrett für tiefergehenden Zugriff. Aufsichtsbehörden werten unbefugten Zugriff auf personenbezogene Daten als Datenschutzverletzung, ganz gleich wie trivial die Technik war, sodass die Rechnung für Offenlegung und Compliance genauso ausfällt wie bei jeder anderen Preisgabe.
Wie verhindern Sie eine BOLA-Schwachstelle?
Setzen Sie eine serverseitige Autorisierungsprüfung für jedes Objekt durch, bei jeder Anfrage, gebunden an die authentifizierte Sitzung statt an irgendetwas, das der Client sendet. Dieser eine Satz ist die Lösung. Der Rest beschreibt nur, wie Sie sie verlässlich machen.
- Standardmäßig verweigern. Der Objektzugriff sollte im Zweifel gesperrt bleiben, sofern nicht eine ausdrückliche Regel besagt, dass der aktuelle Principal es sehen darf. Ein neuer Endpunkt sollte die Sperre erben, nicht den Zugriff.
- Behandeln Sie eine vom Client gelieferte ID niemals als Autorisierungsentscheidung. Die ID sagt Ihnen, welches Objekt. Die Sitzung sagt Ihnen, wer fragt. Die Autorisierung ist die Verknüpfung der beiden, und diese Verknüpfung gehört jedes einzelne Mal auf den Server.
- Grenzen Sie die Abfrage auf den Eigentümer ein. Das beständigste Muster, das wir empfehlen, ist ein objektbezogener Datenzugriff: Fragen Sie
WHERE order.id = :id AND order.owner_id = :currentUserab, statt anhand der ID abzurufen und die Eigentümerschaft erst danach zu prüfen. Eine Zeile, die nicht Ihnen gehört, wird schlicht nie geladen, es gibt also keine Lücke zwischen Laden und Prüfen, die jemand vergessen könnte. - Zentralisieren Sie die Prüfung. Legen Sie die Autorisierung in eine Policy-Schicht oder Middleware, die jeder Resolver und Controller durchläuft, statt eine Eigentumsprüfung in jeden Handler zu kopieren. Verstreute Prüfungen sind genau der Grund, warum ein Endpunkt übersehen wird.
- Autorisieren Sie in GraphQL auf Knoten- und Feldebene. Schützen Sie jeden Resolver, der ein Objekt anhand der ID lädt, einschließlich verschachtelter
node-Abfragen, Connection-Edges und gebündelter Aliase, nicht nur die oberste Query. - Nutzen Sie schwer erratbare IDs als tiefengestaffelte Verteidigung, nicht als die eigentliche Kontrolle. UUIDs verringern die blinde Enumeration, ersetzen aber niemals die Eigentumsprüfung.
Bauen Sie gleich eine Regressionsabdeckung ein. Ein Test, der sich als Nutzer B anmeldet und bei dem Objekt von Nutzer A ein 403 oder 404 erwartet, kostet ein paar Minuten Schreibaufwand und schlägt an dem Tag Alarm, an dem jemand die Abfrage umbaut und dabei stillschweigend die Einschränkung fallen lässt.
Wie CyberXplore hilft
Autorisierung auf Objektebene ist genau die Art von Fehler, die automatisierte Scanner übersehen und manuelle Tests aufdecken, denn sie hängt davon ab, Ihr Datenmodell zu verstehen und den Vergleich mit zwei Konten gegen echte Geschäftslogik durchzuführen. Unser Team für API-Penetrationstests kartiert jeden objekttragenden Endpunkt, wiederholt Anfragen über getrennte Konten hinweg und bestätigt jeden Befund mit einer reproduzierbaren Anfrage wie der obigen, und übergibt Ihnen dann eine Anleitung zur Behebung. Wenn Sie eine BOLA-fokussierte Bewertung Ihrer REST- oder GraphQL-API wünschen, fordern Sie ein Angebot an, und wir schneiden sie auf Ihre tatsächlichen Endpunkte zu.
FAQ
Ist BOLA dasselbe wie IDOR?
Im Grunde ja. IDOR (Insecure Direct Object Reference) ist der ältere, allgemeine Web-Begriff, und BOLA (Broken Object Level Authorization) ist der Name, den OWASP für die Variante auf Objektebene in den API Security Top 10 verwendet. Beide haben dieselbe Grundursache: Der Server handelt anhand einer vom Client gelieferten Objekt-ID, ohne zu bestätigen, dass der Aufrufer für dieses Objekt autorisiert ist. Wir verwenden beide Begriffe für denselben Befund.
Wo steht BOLA in den OWASP API Security Top 10?
Sie ist API1:2023, Broken Object Level Authorization, der Eintrag Nummer eins in der Liste von 2023. Sie entspricht außerdem CWE-639, Authorization Bypass Through User-Controlled Key. Beide in einem Bericht zu nennen, gibt Entwicklern eine präzise, standardgestützte Referenz für diese Fehlerklasse und ihre Behebung.
Verhindern UUIDs IDOR-Fehler in APIs?
Nein. Zufällige UUIDs erschweren die blinde Enumeration erheblich, sie helfen also gegen einen Gelegenheitsangreifer, der IDs errät, doch sie fügen keine Autorisierung hinzu. Wenn die ID über einen Listen-Endpunkt, eine E-Mail, einen Empfehlungslink oder eine GraphQL-Edge durchsickert, was häufig vorkommt, steht das Objekt nach wie vor sperrangelweit offen. Behandeln Sie nicht erratbare IDs als tiefengestaffelte Verteidigung, niemals als die Zugriffskontrolle selbst.
Kann ein Schwachstellenscanner BOLA finden?
Selten von allein. Scanner wissen nicht, welches Objekt zu welchem Nutzer gehört, sie können also nicht erkennen, dass eine valide aussehende 200 in Wirklichkeit die Daten eines anderen Kontos preisgibt. BOLA zuverlässig zu finden erfordert authentifizierte Tests mit mindestens zwei Konten und ein Werkzeug wie Burps Autorize, um Antworten zu vergleichen. Deshalb bleibt sie bei manuellen API-Tests weit oben unter den Befunden.
Betrifft BOLA nur GET-Anfragen?
Nein, und die Schreiboperationen sind oft schlimmer. Eine fehlende Objektprüfung bei PUT, PATCH oder DELETE erlaubt es einem Angreifer, Datensätze zu verändern oder zu löschen, die anderen Nutzern gehören, und ein beschreibbares Feld wie eine E-Mail-Adresse kann sich zu einer Kontoübernahme verketten. Wir testen jede Methode gegen jeden objekttragenden Endpunkt, nicht nur die Lesezugriffe.
Wie schnell können wir einen bestätigten BOLA-Befund beheben?
Oft innerhalb eines Sprints. Die robusteste Lösung besteht darin, jede Datenabfrage auf den authentifizierten Eigentümer einzugrenzen, sodass unbefugte Zeilen nie geladen werden, und diese Prüfung in einer Policy-Schicht zu zentralisieren statt in Code pro Handler. Fügen Sie einen Regressionstest hinzu, der ein 403 oder 404 erwartet, wenn ein Konto das Objekt eines anderen anfragt, und die Fehlerklasse bleibt geschlossen, während sich der Code weiter verändert.



