Pourquoi Securiser une application Laravel ?
L'application web est aujourd'hui un élément essentiel de notre vie quotidienne et professionnelle. La sécurité est donc un enjeu majeur pour tout développeur web, y compris ceux travaillant avec le framework Laravel. Un site ou une application non sécurisée peut être facilement piraté, ce qui entraîne la perte des données personnelles des utilisateurs, les pertes financières et même les dommages à la réputation de l'entreprise.
Un cas d'usage concret : Imaginez que vous développez un site e-commerce en Laravel. Si cette application n'est pas sécurisée, elle est vulnérable aux attaques telles que l'injection SQL, le piratage des comptes utilisateurs et la diffusion de données confidentielles.
Prerequis
- Connaissance avancée du PHP
- Familiarité avec les concepts d'architecture MVC (Model-View-Controller)
- Maîtrise de Laravel (routes, controllers, views, migrations, etc.)
- Connaissance des bases de données SQL et ORM Eloquent
- Compréhension des mécanismes de sécurité HTTP (HTTPS, CSRF, XSS, etc.)
Outils à installer :
- PHP 8.1 ou ultérieur
- Composer (gère les dépendances du projet)
- Node.js (pour les packages frontaux si nécessaire)
- Laravel Installer (pour créer rapidement un nouveau projet)
Installation des outils :
## Installez PHP 8.1 via le gestionnaire de paquets de votre système
sudo apt update && sudo apt install php8.1
## Installez Composer
curl -sS https://getcomposer.org/installer | sudo php -- --install-dir=/usr/local/bin --filename=composer
## Installez Node.js (version recommandée pour Laravel)
sudo apt install nodejs npm
## Installez le Laravel Installer
composer global require laravel/installer
Concepts fondamentaux
1. Authentification et Authorization
L'authentification est le processus de vérifier l'identité d'un utilisateur, tandis que l'autorisation détermine les actions qu'il peut effectuer.
Schema mental :
- Authentification : Utilisateur s'identifie
- Authorization : Utilisateur fait une action spécifique
Code fonctionnel :
// Authentification avec Laravel Breeze
composer require laravel/breeze --dev
php artisan breeze:install
// Migration pour l'utilisateur
php artisan make:migration create_users_table --create=users
// Création du modèle User et de la migration correspondante
php artisan make:model User -m
// Migration de création des utilisateurs (dans db/migrations)
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
2. Hashing des mots de passe
Les mots de passe doivent être stockés en toute sécurité dans la base de données. Laravel utilise le hashage pour ce faire.
Schema mental :
- Hashing : Convertir un mot de passe en une chaîne sécurisée
Code fonctionnel :
// Utilisation du facade Hash
use Illuminate\Support\Facades\Hash;
$hashedPassword = Hash::make('my-secret-password');
if (Hash::check('my-secret-password', $hashedPassword)) {
// Mot de passe correct
}
3. Middleware
Les middleware sont des fonctions qui s'exécutent avant ou après une requête HTTP. Ils sont utilisés pour effectuer des tâches comme l'authentification et la vérification des permissions.
Schema mental :
- Middleware : Filtrage des requêtes HTTP
Code fonctionnel :
// Création d'un middleware personnalisé
php artisan make:middleware CheckAge
// Modification du middleware (app/Http/Middleware/CheckAge.php)
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class CheckAge
{
public function handle(Request $request, Closure $next)
{
if ($request->age <= 18) {
return redirect('home');
}
return $next($request);
}
}
// Enregistrement du middleware dans app/Http/Kernel.php
protected $routeMiddleware = [
// ...
'check.age' => \App\Http\Middleware\CheckAge::class,
];
4. Validation des données
La validation des données est essentielle pour prévenir les injections SQL et les autres attaques.
Schema mental :
- Validation : Vérification des entrées utilisateur
Code fonctionnel :
// Utilisation de la validation dans un controller
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
public function store(Request $request)
{
$validator = Validator::make($request->all(), [
'name' => 'required|max:255',
'email' => 'required|email|unique:users',
'age' => 'integer|min:18',
]);
if ($validator->fails()) {
return redirect('register')
->withErrors($validator)
->withInput();
}
// Validation réussie, continuez les opérations
}
Mise en pratique : projet fil rouge
Pour mettre en pratique ce que nous avons appris, construisons un gestionnaire de tâches simple. Ce projet comprendra :
- Authentification et autorisation des utilisateurs.
- Création, mise à jour et suppression de tâches.
Structure du projet :
task-manager/
├── app/
│ ├── Http/
│ │ ├── Controllers/
│ │ │ ├── TaskController.php
│ │ ├── Middleware/
│ │ │ ├── AuthMiddleware.php
│ │ ├── Routes/web.php
│ ├── Models/
│ │ ├── Task.php
│ ├── Database/
│ │ ├── Migrations/2014_10_12_000000_create_tasks_table.php
├── resources/
│ ├── views/
│ │ ├── auth/
│ │ │ ├── login.blade.php
│ │ ├── tasks/
│ │ │ ├── index.blade.php
│ │ │ ├── create.blade.php
│ ├── js/app.js
├── routes/
│ └── web.php
├── storage/
├── tests/
├── .env.example
├── composer.json
└── package.json
Étapes du projet :
- Création du projet Laravel
laravel new task-manager --api
cd task-manager
- Installation des dépendances
composer require laravel/ui
php artisan ui vue --auth
npm install && npm run dev
- Configuration de la base de données
- Modifiez
.envpour configurer votre base de données.
- Création du modèle et de la migration
php artisan make:model Task -m
- Mise à jour de la migration
// database/migrations/2014_10_12_000000_create_tasks_table.php
Schema::create('tasks', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('description')->nullable();
$table->boolean('completed')->default(false);
$table->foreignId('user_id')->constrained()->onDelete('cascade');
$table->timestamps();
});
- Exécution de la migration
php artisan migrate
- Création du contrôleur pour les tâches
php artisan make:controller TaskController --resource
- Ajout des routes
// routes/web.php
Route::get('/tasks', [TaskController::class, 'index']);
Route::get('/tasks/create', [TaskController::class, 'create']);
Route::post('/tasks', [TaskController::class, 'store']);
Route::get('/tasks/{task}/edit', [TaskController::class, 'edit']);
Route::put('/tasks/{task}', [TaskController::class, 'update']);
Route::delete('/tasks/{task}', [TaskController::class, 'destroy']);
- Création des vues
resources/views/tasks/index.blade.phpresources/views/tasks/create.blade.phpresources/views/tasks/edit.blade.php
- Ajout des styles et scripts
Modifiez
resources/js/app.jspour ajouter du JavaScript personnalisé.
Code final :
// app/Models/Task.php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Task extends Model
{
use HasFactory;
protected $fillable = ['title', 'description', 'completed'];
}
// app/Http/Controllers/TaskController.php
namespace App\Http\Controllers;
use App\Models\Task;
use Illuminate\Http\Request;
class TaskController extends Controller
{
public function index()
{
return view('tasks.index', ['tasks' => auth()->user()->tasks]);
}
public function create()
{
return view('tasks.create');
}
public function store(Request $request)
{
$validatedData = $request->validate([
'title' => 'required|max:255',
'description' => 'nullable',
]);
Task::create($validatedData + ['user_id' => auth()->id()]);
return redirect('/tasks');
}
public function edit(Task $task)
{
return view('tasks.edit', ['task' => $task]);
}
public function update(Request $request, Task $task)
{
$validatedData = $request->validate([
'title' => 'required|max:255',
'description' => 'nullable',
'completed' => 'boolean',
]);
$task->update($validatedData);
return redirect('/tasks');
}
public function destroy(Task $task)
{
$task->delete();
return redirect('/tasks');
}
}
// resources/views/tasks/index.blade.php
@extends('layouts.app')
@section('content')
<h1>Tâches</h1>
<a href="/tasks/create">Ajouter une tâche</a>
<ul>
@foreach ($tasks as $task)
<li>
$task->title
<form action="/tasks/$task->id" method="POST">
@csrf
@method('DELETE')
<button type="submit">Supprimer</button>
</form>
</li>
@endforeach
</ul>
@endsection
// resources/views/tasks/create.blade.php
@extends('layouts.app')
@section('content')
<h1>Ajouter une tâche</h1>
<form action="/tasks" method="POST">
@csrf
<label for="title">Titre</label>
<input type="text" name="title" id="title">
<label for="description">Description</label>
<textarea name="description" id="description"></textarea>
<button type="submit">Ajouter</button>
</form>
@endsection
// resources/views/tasks/edit.blade.php
@extends('layouts.app')
@section('content')
<h1>Modifier une tâche</h1>
<form action="/tasks/$task->id" method="POST">
@csrf
@method('PUT')
<label for="title">Titre</label>
<input type="text" name="title" id="title" value="$task->title">
<label for="description">Description</label>
<textarea name="description" id="description">$task->description</textarea>
<button type="submit">Modifier</button>
</form>
@endsection
Erreurs frequentes et debugging
1. Mauvaise validation des données
## ❌ Mauvais
public function store(Request $request)
{
$task = new Task;
$task->title = $request->input('title');
$task->save();
}
## ✅ Correct
public function store(Request $request)
{
$validatedData = $request->validate([
'title' => 'required|max:255',
'description' => 'nullable',
]);
Task::create($validatedData);
return redirect('/tasks');
}
2. Mauvaise gestion des erreurs d'authentification
## ❌ Mauvais
public function login(Request $request)
{
if (Auth::attempt(['email' => $request->input('email'), 'password' => $request->input('password')])) {
return redirect('/dashboard');
} else {
return back()->withErrors([
'email' => 'Identifiants incorrects',
]);
}
}
## ✅ Correct
public function login(Request $request)
{
if (Auth::attempt($request->only('email', 'password'))) {
return redirect('/dashboard');
}
return back()->withErrors([
'email' => 'Identifiants incorrects',
]);
}
3. Mauvaise gestion des erreurs de redirection
## ❌ Mauvais
public function store(Request $request)
{
Task::create($request->all());
return redirect('/tasks');
}
## ✅ Correct
public function store(Request $request)
{
$validatedData = $request->validate([
'title' => 'required|max:255',
'description' => 'nullable',
]);
Task::create($validatedData);
return redirect()->route('tasks.index')->with('success', 'Tâche ajoutée avec succès');
}
Pour aller plus loin
- Authentification sociale : Utilisez Laravel Socialite pour ajouter des plateformes de connexion telles que Facebook, Google, etc.
- Cryptography : Utilisez Laravel's Crypt facade pour chiffrer et déchiffrer les données sensibles.
- API Security : Apprenez à sécuriser vos API avec OAuth et JWT.
Défi pratique : Ajoutez une fonctionnalité de filtrage des tâches par statut (complétées/non-complétées) dans l'application gestionnaire de tâches.