Zum Inhalt springen

Unzureichende Autorisierung auf Funktionsebene

CWE-285CWE-862OWASP A01:2021Aktualisiert 4. September 20265 Min. Lesezeit

Bei unzureichender Autorisierung auf Funktionsebene bestimmt die Oberfläche, was ein Nutzer sieht, während der Server nicht prüft, was er aufrufen darf. Ein gewöhnlicher Nutzer, der die Adresse einer Verwaltungsfunktion kennt, führt sie einfach aus. Das Verbergen im Menü ist Darstellung; Autorisierung gehört auf den Server.

Eine Verwaltungsfunktion, die nicht im Menü steht, ist für einen gewöhnlichen Nutzer unauffindbar, bis jemand das JavaScript-Bundle öffnet, in dem sämtliche Routen der Anwendung säuberlich aufgelistet sind. Von diesem Moment an besteht der Unterschied zwischen einem gewöhnlichen Nutzer und einem Administrator nur noch darin, ob der Server die Anfrage abweist. Genau dafür zu sorgen ist die eigentliche Arbeit.

Was ist Autorisierung auf Funktionsebene?

Jede Anwendung kennt Funktionen, die nicht für jeden gedacht sind: Nutzer verwalten, Rollen vergeben, Exporte ausführen, Einstellungen ändern, Daten löschen. Autorisierung auf Funktionsebene ist die Prüfung, die feststellt, ob der Anfragende genau diesen Vorgang ausführen darf.

Unzureichende Autorisierung auf Funktionsebene, international Broken Function Level Authorization oder BFLA, bedeutet, dass diese Prüfung allein in der Oberfläche stattfindet. Die Schaltfläche wird nicht angezeigt, der Menüpunkt fehlt, die Route steht nicht in der Navigation. Der Endpunkt jedoch existiert, ist erreichbar und führt aus, worum er gebeten wird, sobald jemand die Anfrage unmittelbar sendet.

Der Denkfehler besteht darin, das Frontend für einen Torwächter zu halten. Das ist es nicht: Es ist eine Darstellung. Was ein Nutzer sieht, bestimmt das Frontend; was ein Nutzer kann, bestimmt allein der Server. Stellen Sie sich einen Aufzug vor, bei dem die Taste für die Vorstandsetage überklebt ist. Solange niemand daran denkt, das Klebeband zu entfernen, funktioniert es. Doch die Taste ist noch da, und sie tut ihren Dienst.

Wie wird fehlende Autorisierung auf Funktionsebene ausgenutzt?

Verwundbar:

// Angemeldet, aber keine Prüfung der Rolle
app.post('/api/verwaltung/nutzer/:id/rolle', erfordertAnmeldung, async (req, res) => {
  await nutzerRepo.setzeRolle(req.params.id, req.body.rolle);
  res.json({ ok: true });
});

In der Oberfläche ist dieser Endpunkt nur aus einer Verwaltungsmaske heraus erreichbar, die gewöhnliche Nutzer nie zu sehen bekommen. Der Endpunkt selbst verlangt jedoch nur eine gültige Sitzung. Ein Angreifer findet die Adresse im Frontend-Bundle:

// Im JavaScript der Anwendung, für jeden sichtbar
const routen = {
  profil: '/api/profil',
  nutzerVerwalten: '/api/verwaltung/nutzer',
  rolleAendern: '/api/verwaltung/nutzer/:id/rolle',
};

Und sendet anschließend mit seinem eigenen, gewöhnlichen Konto:

POST /api/verwaltung/nutzer/4471/rolle HTTP/1.1
Cookie: sid=<eigene gültige Sitzung>
Content-Type: application/json

{"rolle":"administrator"}

HTTP/1.1 200 OK

Er hat sich soeben selbst zum Administrator gemacht. Es wurde kein Passwort erraten, keine Einschleusung ausgeführt und keine Sitzung gestohlen; es wurde eine Anfrage an einen Endpunkt gesendet, der ihn zuvorkommend bedient hat.

Sicher:

// Autorisierung je Route, ausdrücklich hinterlegt
const erfordertRolle = (...rollen) => async (req, res, next) => {
  const nutzer = await nutzerRepo.finde(req.nutzer.id);   // aktuelle Rolle
  if (!nutzer || !rollen.includes(nutzer.rolle)) {
    await auditlog.schreibe('Autorisierung verweigert', {
      nutzer: req.nutzer.id, route: req.originalUrl,
    });
    return res.sendStatus(404);
  }
  next();
};

app.post('/api/verwaltung/nutzer/:id/rolle',
  erfordertAnmeldung,
  erfordertRolle('administrator'),
  async (req, res) => {
    await nutzerRepo.setzeRolle(req.params.id, req.body.rolle);
    res.json({ ok: true });
  },
);

// Auffangnetz: Jede Route ohne ausdrückliche Rechte wird abgewiesen
app.use('/api', (req, res) => res.sendStatus(404));

Die Prüfung sitzt nun an der Route selbst und verwendet die aktuelle Rolle aus der Datenbank statt eines Werts aus der Sitzung. Das Auffangnetz am Ende ist mindestens ebenso wichtig: Ein neuer Endpunkt, bei dem die Entwicklerin die Autorisierung vergisst, fällt dadurch zu statt auf. Das ist der Unterschied zwischen einem Fehler, der beim Testen auffällt, und einem Fehler, der in der Produktion zur Schwachstelle wird.

Fassen Sie Verwaltungsfunktionen unter einem eigenen Pfadpräfix zusammen und setzen Sie die Rollenprüfung auf diesen gesamten Pfad statt je Endpunkt. So muss niemand beim Hinzufügen der nächsten Funktion daran denken, und genau dieses Vergessen ist die häufigste Ursache dieses Befunds.

Welche Auswirkungen hat fehlende Autorisierung auf Funktionsebene?

Der Schweregrad ist hoch bis kritisch, da das Ergebnis meist auf eine Erhöhung der eigenen Rechte hinausläuft. Ein Nutzer, der sich selbst zum Administrator machen kann, erhält damit Zugriff auf alles, was die Anwendung zu bieten hat.

Auch ohne diesen unmittelbaren Weg sind die Folgen beträchtlich. Verwaltungsfunktionen sind per Definition die Funktionen mit der größten Reichweite: das Exportieren aller Kundendaten, das Löschen von Datensätzen, das Ändern sicherheitsrelevanter Einstellungen, das Abschalten der Zwei-Faktor-Authentifizierung für andere Konten. Ein einziger ungeschützter Endpunkt dieser Art genügt für einen erheblichen Vorfall.

Was die nachträgliche Feststellung erschwert, ist, dass alles normal aussieht. Der Angreifer nutzt sein eigenes gültiges Konto, die Anfrage ist korrekt aufgebaut, und die Antwort ist ein 200. Ohne Protokollierung von Autorisierungsentscheidungen gibt es keine Spur, aus der hervorginge, dass jemand eine nicht für ihn bestimmte Funktion aufgerufen hat.

Wie erkennt man fehlende Autorisierung auf Funktionsebene?

Ein Tester erfasst zunächst sämtliche Endpunkte und schaut dabei ausdrücklich über das hinaus, was die Oberfläche zeigt. Das JavaScript-Bundle des Frontends ist dabei die ergiebigste Quelle: Es enthält häufig alle Routen, einschließlich jener der Verwaltungsmasken. Ebenso werden API-Dokumentation, ältere Versionen und vorhersehbare Benennungen genutzt.

Anschließend wird jeder gefundene Endpunkt mit einem Konto mit minimalen Rechten aufgerufen. Gelingt die Anfrage, steht der Befund. Dabei wird jede Methode gesondert geprüft, denn die Autorisierung sitzt mitunter auf GET und nicht auf POST oder DELETE. Auch die klassischen Umwege werden ausprobiert: eine abweichende Schreibweise des Pfads, eine ältere API-Version, die zu derselben Funktion führt, oder ein Header, der eine Rolle mitsendet, der die Anwendung zu Unrecht vertraut. AssistSec führt diesen Test mit Konten in jeder verfügbaren Rolle durch, denn die interessanten Lücken liegen meist nicht zwischen anonym und angemeldet, sondern zwischen zwei Stufen angemeldeter Nutzer.

Wie verhindert man fehlende Autorisierung auf Funktionsebene?

  • Prüfen Sie bei jedem Endpunkt serverseitig, ob der Nutzer die zugehörige Funktion ausführen darf.
  • Verweigern Sie standardmäßig und erlauben Sie nur ausdrücklich, damit eine vergessene Prüfung zu einer abgewiesenen Anfrage führt.
  • Fassen Sie Verwaltungsfunktionen unter einem eigenen Pfad mit einer zentralen Rollenprüfung zusammen.
  • Rufen Sie die Rolle bei jeder Anfrage aus der Datenbank ab, nicht aus der Sitzung oder einem Token.
  • Prüfen Sie jede HTTP-Methode gesondert; die Autorisierung fehlt oft bei genau einer davon.
  • Betrachten Sie das Verbergen von Schaltflächen und Menüpunkten als Darstellung, nie als Absicherung.
  • Entfernen oder schirmen Sie ältere API-Versionen ab, denn diesen fehlen häufig die neueren Prüfungen.
  • Vertrauen Sie keiner Rolle und keinen Rechten, die in einem Header oder Parameter mitgesendet werden.
  • Protokollieren Sie verweigerte Autorisierungsversuche, damit die Erkundung durch einen angemeldeten Nutzer sichtbar wird.

Quellen

Häufige Fragen

Was unterscheidet es von BOLA?

BOLA betrifft die Frage, ob Sie auf ein bestimmtes Objekt zugreifen dürfen; BFLA die Frage, ob Sie eine bestimmte Funktion ausführen dürfen. Bei BOLA gelangt ein Kunde an die Rechnung eines anderen Kunden, bei BFLA führt ein gewöhnlicher Nutzer eine Administratorfunktion aus. Beides muss gesondert geprüft werden.

Genügt es, Schaltflächen zu verbergen?

Nein, und darin liegt der Kern dieses Befunds. Was die Oberfläche zeigt, ist eine Frage der Darstellung; der Server führt aus, worum er gebeten wird. Jeder kann eine Anfrage unmittelbar senden. Der einzige Ort, an dem Autorisierung zählt, ist der Server.

Warum werden Endpunkte gefunden, die nirgends stehen?

Aus dem JavaScript-Bundle des Frontends, das häufig sämtliche Routen einschließlich der Administratorfunktionen enthält. Weiter aus API-Dokumentation, aus vorhersehbarer Benennung und aus älteren Versionen der API. Unbekanntheit ist kein Schutz.

Wie erzwinge ich das strukturell?

Indem die Prüfung standardmäßig verweigert und nur ausdrücklich erlaubt. Eine zentrale Schicht, die jede Route ohne hinterlegte Rechte blockiert, macht aus einer vergessenen Prüfung eine Störung beim Testen statt einer Schwachstelle in der Produktion.

Verwandte Artikel

Zum Suchen / drücken · Esc