Laravel: Wie du Sicherheitslücken mit richtiger Authentifizierung verhinderst

Du hast bestimmt schon von Dingen wie Daten-Leaks oder Identitätsdiebstahl im Web gehört. Da stellt sich die Frage: Wie verhinderst du, dass so etwas in deiner eigenen Web-Applikation passiert?

Das lässt sich leider nicht in einem Blogartikel beantworten. Deshalb konzentrieren wir uns darauf, wie dir das Laravel-Framework unter die Arme greift, damit weitverbreitete Sicherheitslücken gar nicht erst aufkommen.

Die OWASP (Open Web Application Security Project) Foundation hat ein Dokument mit den Top 10 Sicherheitslücken in Web-Applikationen im Jahr 2021 veröffentlicht. An Stelle Nummer 1 steht dort das Problem “Broken Access Control”. Legen wir unseren Fokus also darauf – und wie wir mithilfe von Laravel diesem Problem entgegenwirken können.

Was ist Broken Access Control?

Broken Access Control bedeutet, dass du nicht die Kontrolle darüber hast, wer auf welche Daten oder Prozesse deiner Web-Applikation zugreift. Das kann verschiedene Ursachen haben. Einige, die auch die OWASP Foundation in ihrem Dokument beschreibt, möchten wir dir kurz vorstellen, bevor wir dir erklären, wie du sie behebst.

Deny by Default-Verletzung

Deny by Default bedeutet, dass du zunächst gar keinen Zugriff auf deine Web-Applikation erlaubst. Dann prüfst du für jede Aktion, ob diese für bestimmte Usertypen freigegeben sein sollte, und schaltest dann nur diese Aktion für nur diesen Usertyp frei. Wenn dieses Prinzip nicht eingehalten wird, entstehen schnell Sicherheitslücken – einfach weil du den Überblick darüber verlierst, wem du wo den Zugriff verweigern musst.

URL-Manipulation

Das kann passieren, wenn du Zugriff auf gewisse Teile deiner Applikation erlaubst, wenn ein Angreifer es schafft, die URL dorthin zu “erraten”. Beispielweise könnte unter www.beispiel.de/entwurf/7 ein User den Artikel-Entwurf mit der ID 7 sehen. Er soll nur sichtbar für den User selbst sein.

Wenn der User aber durch das Ausprobieren anderer IDs in der URL auch auf die Entwürfe anderer User zugreifen kann, spricht man von URL-Manipulation.

Nutzungsprivilegien nicht einhalten

Vielleicht prüfst du zwar, ob ein User authentifiziert ist, vergisst aber zu prüfen, ob dieser User auch die Rechte hat, die benötigt sind, um eine bestimmte Aktion auszuführen. Stell dir vor, die Seite www.beispiel.de/artikel/42 zeigt den Artikel mit der Id 42 in deiner Web-Applikation an. Das Recht, diesen Artikel zu sehen, haben alle eingeloggten User. Das Recht, ihn zu löschen, haben aber nur Administratoren. Wenn es einem Standard-User möglich ist, die Lösch-Aktion trotzdem auszuführen, dann sind die Nutzungsprivilegien der Admins nicht geschützt.

Wie kannst du Sicherheitslücken entgegenwirken?

Sicherheitslücken entstehen häufig, wenn gewisse Prinzipien nicht eingehalten werden und du den Überblick über deine Web-Applikation verlierst, während sie weiterentwickelt wird.

Wenn du deine Web-Applikation auf Laravel aufbaust, hilft dir das Laravel-Framework, den Überblick zu behalten und die Prinzipien anzuwenden. Wir zeigen dir heute, wie du die Authentifizierung in Laravel konfigurierst – ein wichtiger Baustein zur Sicherung deiner Laravel-Applikation.

Routes in Laravel

Schauen wir uns zunächst an, wo die Authentifizierung meistens ansetzt.
Der wichtigste Zugriffspunkt auf eine Web-Applikation sind die Anfragen, die der Webbrowser an den Server sendet. Solche Anfragen schickt der Browser sowohl beim ersten Aufruf der Seite als auch bei jedem Klick auf einen Link oder Menüpunkt auf dieser Seite. Hier ergibt sich daher auch ein großes Einfallstor für Angriffe und schädliche User-Anfragen. In Laravel-Anwendungen helfen dir die Routes dieses Einfallstor zu sichern.

Die Idee hinter Routes ist, dass du jede Möglichkeit, eine Anfrage an deine Webanwendung zu senden, bewusst vorgeben musst. Gleichzeitig gibst du an, wie die Anfrage weiterverarbeitet werden soll und ob gewisse Dinge auf jeden Fall geprüft werden sollen – beispielsweise, ob der User überhaupt angemeldet ist – womit wir wieder bei der Authentifizierung wären.

Ein Beispiel:
Deine Applikation hat eine Login-Seite, auf der man Login-Namen und Passwort eingeben muss. Die Adresse dieser Seite ist:

Um diese Seite aufrufbar zu machen, würdest du folgende Route anlegen:

Hier wird zunächst festgehalten, dass es den Pfad /login überhaupt gibt – dass er also erreichbar ist. Danach wird angegeben, welcher Code ausgeführt werden soll, um die Anfrage weiterzuverarbeiten (hier: die Funktion “show” in der Klasse “LoginController”).

Diese Zeile Code lässt sich aber noch erweitern. Machen wir dies an einer analogen Route fest:

Die Syntax ist gleich geblieben. Wirklich neu an dieser Zeile ist das Ende “middleware(‘auth’)”. Das Middleware-Schlüsselwort signalisiert, dass jeder Aufruf dieser Route einer vorherigen Prüfung bedarf. Was geprüft wird, legt der übergebene Parameter fest. In unserem Beispiel zeigt das Wort “auth” an, dass die Authentication-Middleware verwendet werden soll. Sie sorgt dafür, dass nur ein authentifizierter User diese Seite aufrufen darf. Aber wie funktioniert das?

Die Authentifizierung

Viele Web-Applikationen müssen (mindestens) zwei unterschiedliche Arten der Authentifizierung ermöglichen:

  • den Login mit anschließender Authentifizierung via Session und Cookie
  • den Login mit anschließender Authentifizierung via API-Token

Die Auth-Middleware von Laravel bietet dir die Möglichkeit, nur authentifizierte User zu bestimmten Routen zuzulassen.

Statt nur ->middleware(‘auth’) zu verwenden, kann man der AuthMiddleware auch Parameter übergeben, beispielsweise so: ->middleware(‘auth:web,api’). Man kann beliebig viele Komma getrennte Strings hinter dem Doppelpunkt festlegen. Middlewares interpretieren alles hinter dem Doppelpunkt als Parameter. Die AuthMiddleware interpretiert alle übergebenen Parameter als Indizes für Guards.

Hinweis: Wenn kein Guard als Parameter übergeben wird (also nur ‘auth’), dann wird der Default-Guard verwendet.

Welche Guards es gibt, wird in der config/auth.php festgelegt. Das schauen wir uns zum Ende noch mal genauer an.

Zunächst wollen wir die Frage klären, was die AuthMiddleware mit den Guards macht.
Sie geht die Guards der Reihe nach durch und prüft, ob die aktuelle Anfrage durch diesen Guard authentifizierbar oder schon authentifiziert ist. Falls das der Fall ist, wird dieser Guard als Standard für den Rest der Anfrageverarbeitung verwendet und die AuthMiddleware wurde erfolgreich durchlaufen. Erst jetzt wird der Code ausgeführt, der für die Route festgelegt ist!

Guards: Konfigurationen der Authentifizierungsmöglichkeiten

Ein Guard ist eine Art von Authentifizierung, die leicht konfiguriert werden kann. Was du konfigurieren kannst, ist in erster Linie,

  • welchen Driver der Guard verwendet (Laravel bringt die Driver “session” und “token” mit) und
  • welchen Userprovider der Guard verwendet. Userprovider haben wiederum selbst Driver (Laravel bringt die Driver “eloquent” und “database” mit) sowie weitere Parameter.

 

Anhand der Konfiguration eines Guards wird festgelegt, wie die Authentifizierung geprüft wird. Der Guard-Driver legt das grundsätzliche Prinzip der Authentifizierung fest (beispielsweise “Session” oder “Token”).
Der Userprovider legt die Quelle fest, in der nach dem zu authentifizierenden User gesucht wird. Hier bestimmt der Driver wiederum die Struktur dieser Quelle (zum Beispiel ORM oder Datenbank). Die weiteren Parameter bestimmen, wo in dieser Quelle zu suchen ist (beispielsweise in einer bestimmten Datenbanktabelle).

In der config/auth.php lassen sich beliebig viele Guards konfigurieren. Schauen wir uns folgendes Beispiel an:

Hier sehen wir vier verschiedene Guards. Zwei verwenden als Driver den SessionGuard (‘session’), zwei verwenden den TokenGuard (‘token’).
Die verschiedenen Userprovider (‘provider’) sind weiter unten in derselben Datei ebenfalls konfiguriert:

Wenn du die Inhalte vergleichst, wirst du feststellen, dass alle Kombinationen aus Standard-Guards (Session und Token) und Standard-Userprovidern (Eloquent und Database) vorkommen, und zwar wie in folgender Tabelle angegeben:

Session Token
Eloquent web system_api
Database admins api

Mit dieser Konfiguration ergeben sich die folgenden Authentifizierungsmöglichkeiten, mit denen du deine Routes schützen kannst:

web: Dieser Guard prüft, ob in der aktuellen Session (definiert über die Session-ID, die im Request mitgeschickt wird) eine ID vorhanden ist, die einer ID im Eloquent-Model “User” entspricht. Falls ja, ist dies der nun authentifizierte User.

Hinweis: Das klingt erst mal nicht sicher. Entscheidend ist hier, dass die Session-ID eine zufällig generierte Zeichenkette ist, die nur der Browser des Users und der Server kennen.

admins: Dieser Guard prüft, ob in der aktuellen Session (definiert über die Session-ID, die im Request mitgeschickt wird) eine ID vorhanden ist, die einer ID in der Datenbank-Tabelle admins entspricht. Falls ja, war die Authentifizierung erfolgreich.

api: Dieser Guard prüft, ob im aktuellen Request ein Schlüssel-Wert-Paar mit dem Schlüssel “api_token” (auch das ist konfigurierbar!) vorhanden ist. Ansonsten wird geprüft, ob der Http-Header einen Bearer-Token oder ein Passwort enthält. Falls ja, wird in der Datenbanktabelle “api_tokens” nach diesem Wert in der Spalte “api_token” (auch das ist konfigurierbar!) gesucht. Wird er gefunden, war die Authentifizierung erfolgreich.

system_api: Hier wird wie bei “api” zunächst der Token im Request gesucht. Ist er gefunden, wird geprüft, ob es ein Eloquent-Model “ExternalSystem”, dessen Attribut “api_token” (konfigurierbar!) dem Token aus dem Request entspricht. Falls ja, ist dieses ExternalSystem nun der authentifizierte User.

Im folgenden Screenshot siehst du, wie du diese Konfigurierungen in deiner Laravel-Applikation einsetzt, um bestimmte Bereiche auf unterschiedliche Art und Weise zu schützen.

Fazit

Erinnern wir uns noch einmal an unser Eingangsproblem. Die OWASP Foundation hat festgestellt, dass Broken Access Control zu den häufigsten Sicherheitslücken im Web gehört. Broken Access Control entsteht beispielsweise durch das Nicht-Einhalten des “Deny by Default”-Prinzips, durch die Möglichkeit, URLs zu manipulieren oder dadurch, sich als ein User mit höheren Privilegien auszugeben.

  • Dank der Routes in Laravel kannst du nun das “Deny by Default”-Prinzip viel leichter einhalten, indem du generell alle Routes mit der AuthMiddleware schützt.
  • Durch das Verwenden verschiedener Guards kannst du ganz leicht festlegen, welche Bereiche nur für bestimmte User – zum Beispiel Administratoren – verfügbar sind.
  • Eine Manipulation von URLs, um Objekte fremder User zu sehen oder zu manipulieren, ist dadurch, dass die AuthMiddleware bei jedem einzelnen Aufruf prüft, wer der User ist, ebenfalls leicht möglich. Du kannst nämlich jederzeit prüfen, ob der User, der als Besitzer*in eines Objekts festgelegt ist, dem User entspricht, der authentifiziert ist. Die ID des aktuell authentifizierten Users erfährst du ganz einfach über die Funktion Auth::id().

Die verschiedenen Konfigurationen von Guards musst du nur einmal schreiben und kannst sie danach überall anwenden. Das erhöht die Übersicht über die Zugriffe, die du gewährst.

Die Implementierung von den häufig verwendeten Authentifizierungstypen, “Session” und “Token” bringt Laravel bereits mit, sodass du dir um die korrekte Implementierung keine Sorgen machen musst – du kannst dich darauf konzentrieren, die jeweilige Implementierung dort anzuwenden, wo sie notwendig ist.

Wir haben in diesem Artikel viele Themengebiete angeschnitten. Darum noch ein paar Tipps:

  • Routes bieten viel mehr Möglichkeiten, als wir in diesem Artikel skizzieren konnten.
  • Du kannst selbst weitere Guards schreiben, die den Ansprüchen deiner Applikation genügen.
  • Laravel bietet bereits einige Implementierungen dafür, wie sich User einloggen können – um danach über die AuthMiddleware authentifiziert zu sein. Auch Multi-Faktor-Authentifizierung und ein Login über Google- oder Facebook-Credentials sind leicht einzurichten.
  • Um komplexere Userrechte festzulegen, bietet Laravel Gates und Policies an.

Welches Thema sollen wir als Nächstes erklären?

Es gibt viel mehr Features, die die Sicherheit von Laravel-Applikationen erhöhen und die wir hier noch nicht angesprochen haben. Wenn dich das Thema interessiert, würden wir mit unserem Blog gerne in Zukunft noch viel tiefer einsteigen. Gib uns doch ein kurzes Feedback, ob dich dieser Blogartikel weitergebracht hat und was du gerne als Nächstes lesen möchtest.

Wobei können wir dich sonst noch unterstützen?

Neues Projekt

Du hast eine Idee für eine digitale Lösung und suchst einen Partner, der dich begleitet?

Verstärkung für dein Projekt

Du hast bereits eine Anwendung und suchst Verstärkung in der Entwicklung?

Artikel teilen

Mehr aus unserem Blog

5 Jahre Lean Ocean – Das Interview

Vor 5 Jahren ist Lean Ocean in einem WG-Zimmer gestartet. Und heute hat das Unternehmen nichts von seinem Startup Flair verloren – nur die Büros sind schicker geworden.
Im Video-Interview werfen unsere Geschäftsführer Oliver und Stephan zusammen einen Blick auf die Entwicklung von Lean Ocean, gemeinsame Meilensteine und was die Arbeit bei Lean Ocean prägt.

Ein Tag als Softwareentwickler bei Lean Ocean

Was macht eigentlich ein Softwareentwickler bei Lean Ocean und wie sieht ein üblicher Arbeitstag aus? Das erzählt dir Norbert im folgenden Blogartikel! Wir haben Norbert, einen unserer Developer, einen Tag lang begleitet und über die Schulter geschaut. Vom ersten Kaffee zum wohlverdienten Feierabend– hier erhältst du spannende Einblicke in einen abwechslungsreichen Arbeitstag.

Von der Idee zum Feature

Wie sieht es eigentlich bei Lean Ocean hinter dem Code aus? Wie läuft so ein Projekt ab und wie wird aus einer Idee dann ein richtiges Feature? In diesem Artikel beantworten dir Oliver und Tom die wichtigsten Fragen zu unserem brandneuen Format #behindthecode. Als erstes geht Oliver als CTO von Lean Ocean auf den Entwicklungsprozess von Features ein und dann gibt uns unser Projektmanager Tom noch ein paar Antworten.

Oliver Holz

Oliver Holz

holz@lean-ocean.com