In deze blogpost gaan we dieper in op een aantal veelvoorkomende Laravel beveiligingsfouten die ik ben tegengekomen in projecten, persoonlijk heb gemaakt of zelfs ben tegengekomen op door Stack Overflow goedgekeurde antwoorden. We zullen het kort hebben over bestandsvalidatie, massatoewijzing en Laravel's query builder. Het doel van deze blog is om te laten zien hoe kleine, gemakkelijk te vermijden fouten een grote impact kunnen hebben op de beveiliging van je applicatie. En hopelijk om te voorkomen dat je ze in de toekomst maakt. Dus laten we beginnen!

Bestand valideren

Laravel biedt een robuust en veilig bestandssysteem waarmee ontwikkelaars bestanden kunnen opslaan en ophalen uit lokale of cloud-opslag. Hieronder staat wat code, rechtstreeks van Stackoverflow, om het uploaden van een avatar naar een profiel af te handelen:

Kun je zien hoe een aanvaller misbruik zou kunnen maken van het volgende fragment?

public function storeImage(Request $request)
{
	$request->validate([
		'image' => 'required|image|mimes:jpeg,png,jpg,gif,svg|max:2048',
	]);

	$imageName = Str::random(16) . '.' . $request->image->getClientOriginalExtension();

	Storage::disk('public')->putFileAs("avatars", $request->image, $imageName);

	return back()->with('success','You have successfully uploaded your avatar!');
}

Stel, een aanvaller wil een .html bestand met een XSS (Cross-site scripting) payload uploaden naar je server. Je zou verwachten dat Laravel's server-side validatie image en mimes:jpeg,png,jpg,gif,svg dit zou oplossen.

Sidenote: Dit is geen bug in Laravel, maar gewoon hoe mime type controle werkt.

De cruciale fout die wordt gemaakt is het gebruik van Laravel's getClientOriginalExtension methode om de extensie van het bestand direct uit het verzoek te halen. In plaats daarvan willen we in dit scenario gebruik maken van:

$request->image->extension();

Dit zal het mime type van het bestand raden op basis van de inhoud van het daadwerkelijke bestand in plaats van wat wordt ontvangen van de client.

Een andere veilige manier om hiermee om te gaan is door Laravel's put methode te gebruiken om bestanden op te slaan:

Storage::disk('public')->put(Str::random(16), $request->image);

Dit zal automatisch je bestandsnaam vervangen door een willekeurige hash en de juiste extensie toevoegen.
De belangrijkste afleiding hier is om nooit te vertrouwen op gebruikersinvoer, vooral als het gaat om het uploaden van bestanden.

 

 

A registration form for a user

Massa toewijzing

Kun jij het beveiligingslek in deze code vinden?

Gebruikersmodel

class User extends Model {

    protected $fillable = ['username', 'email', 'password', 'role'];

}

Registercontroller

class RegisterController
{
  public function create(Request $request) 
  {
    $request->validate([
      'username' => 'required|string',
      'email' => 'required|email|unique:users',
      'password' => 'required|string|min:12|confirmed',
    ]);

    $user = new User();
    $user->role = 'guest'
    $user->fill($request->all());
    $user->save();

    return response()->json(['success' => true],201);
  }
}

Als een kwaadwillende gebruiker het registratieverzoek vervalst en "rol": "admin" toevoegt aan de payload van het formulier. Laravel zou deze gebruiker graag toegang geven tot je hele systeem.

Dit komt doordat $request→all() niet alleen gevalideerde gegevens uit het verzoek haalt, maar ALLE gegevens. In combinatie met de rol die is toegevoegd aan de $fillable property van het model, zou de gebruiker worden aangemaakt met de rol "admin".

Voorkom dit door $request→validated() te gebruiken om alleen gevalideerde invoer op te halen uit je request. Of zorg ervoor dat je invulbare eigenschappen correct zijn ingesteld.

Bonuspunten als je hebt gezien dat het wachtwoord in platte tekst wordt opgeslagen ;)

Query builder parameterbinding

SQL-injectie is een veel voorkomende aanvalsvector voor webtoepassingen, en Laravel is daarop geen uitzondering. Het treedt op wanneer een aanvaller kwaadaardige SQL-code kan invoeren in de invoervelden of query-strings van een webtoepassing.

Hier is een voorbeeld van SQL-injectie met behulp van de query builder van Laravel:

//User input
$search = "1; DROP TABLE users;";

DB::table('users')->whereRaw("name = " . $search)->get();

Deze code is kwetsbaar voor SQL-injectie omdat de aanvaller willekeurige SQL-code kan uitvoeren door de variabele $search in te stellen op een tekenreeks die SQL-opdrachten bevat. In dit geval kan de aanvaller de hele tabel users verwijderen door $search in te stellen op "1; DROP TABLE users;".

Om SQL injectie aanvallen te voorkomen, moet je altijd gebruik maken van Laravel's query builder of parameter binding bij het construeren van SQL queries.

Voorbeeld van parameter binding:

$search = "1; DROP TABLE users;";

DB::table('users')->whereRaw("name = ?", $search)->get();

Conclusie

Hoewel de bovenstaande voorbeelden voor sommigen voor de hand liggend kunnen zijn, hoop ik dat dit artikel het belang illustreert van een goed begrip van de innerlijke werking van een framework, zelfs als het naadloos lijkt om te gaan met beveiliging. Ondanks Laravel's beginnersvriendelijke aard en geminimaliseerde overhead voor ontwikkelaars, vergeet niet om voorzichtig te blijven en zelfgenoegzaamheid te vermijden.

Op zoek naar Laravel-experts?

Auteur: Robbe Reygel
PHP developer

More insights

Test Driven Development - toepassing op een project

TDD, of voluit Test Driven Development, is een aanpak van ontwikkeling waarbij we vertrekken van het schrijven van tests. 

Auteur: Sarah Jehin
PHP developer
Sarah Jehin
development

De OSLO-standaard: hoe gestandaardiseerde gegevensuitwisseling ons verder brengt

De OSLO-standaard is een term die je misschien wel eens hebt horen vallen in de context van gegevensuitwisseling en digitale transformatie, maar wat houdt het precies in en wat zijn de voordelen ervan?

Auteur: Benjamin Verhaegen
PHP Developer
benjamin_verhaegen
shaking_hands_black_white

De toekomst van web applicaties: wat kunnen we verwachten?

In de afgelopen jaren hebben web applicaties een enorme evolutie doorgemaakt. Maar wat heeft de toekomst voor ons in petto? Je ontdekt het allemaal in deze blog.

Author: Tom Van den Eynden
Web Architect | Coordinator
Tom Van den Eynden
computerscherm met code

Het verschil tussen gegevensbeheer en gegevensverwerking in een digitale economie

Gegevens zijn cruciaal voor bedrijven en het begrijpen van de verschillen tussen gegevensbeheer en gegevensverwerking kan verwarrend zijn. In dit artikel zullen we deze verschillen in de digitale economie nader bekijken om hun doelen en toepassingen beter te begrijpen.

Author: Tom Van den Eynden
Web Architect | Coordinator
Tom Van den Eynden
gegevensverwerking

Adressen register & GEOpunt API

Zelf al eens voor de keuze gestaan of je Google maps, openstreetmaps, of een andere GIS provider zou moeten gebruiken voor adres suggesties? Mocht je enkel Belgische adressen nodig hebben, lees dan zeker verder!

Author: Noah Gillard
PHP / Laravel Developer
Noah Gillard AI generated Face
Logo vlaamse overheid

Next.js: Het zoveelste framework?

Zowat om de 10 jaar komt er nieuwe technologie boven drijven, die een verandering teweeg brengt in de manier waarop we software ontwikkelen. Is Next.js deze nieuwe technologie?

Auteur: Dries Cappon
UX, Design, React.js, Next.js
Dries Cappon
Next.js