La sécurité n'est pas un sujet pour les grandes entreprises
Il y a une idée reçue tenace : la sécurité web, c'est pour les grandes structures avec des équipes dédiées. Les petits sites, les portfolios, les outils internes ne seraient pas des cibles intéressantes.
C'est faux. Les attaques automatisées ne font pas de discrimination. Un formulaire de contact non protégé sur un site vitrine de cinq pages peut servir de relais spam. Un mot de passe d'administration en clair dans un fichier .env versionné peut compromettre l'ensemble d'une infrastructure client. Ce n'est pas une question de taille : c'est une question de discipline.
Voici ce que j'applique sur chaque projet, sans exception.
HTTPS partout, sans négociation
En 2026, déployer un site en HTTP non chiffré n'est plus acceptable. Les navigateurs affichent des avertissements, les moteurs de recherche pénalisent, et les données transitent en clair sur le réseau.
Sur o2switch (mon hébergeur), Let's Encrypt est intégré au panneau de contrôle. Activer le certificat SSL prend deux minutes. Ensuite, dans Laravel, le fichier .env fixe APP_URL en https://, et le middleware RedirectIfHttp (ou la configuration Apache via .htaccess) redirige toutes les requêtes HTTP vers HTTPS. Aucune exception.
CSRF : Laravel le gère, mais encore faut-il ne pas l'oublier
Laravel inclut une protection CSRF (Cross-Site Request Forgery) activée par défaut sur toutes les routes POST, PUT, PATCH et DELETE. Chaque formulaire Blade doit inclure @csrf : c'est le token de validation qui prouve que la requête vient bien d'une page servie par l'application.
L'erreur courante : oublier le token sur un formulaire créé rapidement, ou désactiver la protection CSRF pour une route "parce que ça bloque une intégration". La bonne pratique est d'utiliser les routes API avec un token Bearer si une intégration tierce en a besoin, plutôt que de désactiver la protection globalement.
Validation des entrées : côté serveur, toujours
La validation côté client (JavaScript, HTML5 required) est une aide à l'expérience utilisateur. Ce n'est pas une mesure de sécurité : n'importe qui peut désactiver JavaScript ou envoyer une requête HTTP directement.
Toute donnée entrante est validée côté serveur dans Laravel, via les FormRequest ou la façade Validator. Types, longueurs maximales, formats (email, URL, date), valeurs acceptées : rien n'entre dans la base de données sans avoir passé cette validation.
XSS : Blade encode automatiquement
Les attaques XSS (Cross-Site Scripting) consistent à injecter du code JavaScript dans une page via des données utilisateur. Blade protège contre ça par défaut : la syntaxe {{ $variable }} encode automatiquement les caractères dangereux (<, >, ", &). Un <script> injecté dans un champ de formulaire ne s'exécutera jamais.
La seule exception : {!! $variable !!}, qui affiche le contenu brut sans encodage. J'utilise cette syntaxe uniquement pour du contenu que je contrôle entièrement (HTML généré par mon propre code, comme le contenu Markdown converti en HTML via league/commonmark). Jamais pour des données utilisateur.
Requêtes SQL : Eloquent et les requêtes préparées
Les injections SQL sont l'une des vulnérabilités les plus anciennes et les plus documentées. Eloquent, l'ORM de Laravel, utilise des requêtes préparées avec des paramètres liés : les données utilisateur ne sont jamais interpolées directement dans une chaîne SQL.
Quand j'ai besoin d'une requête brute (cas rare), j'utilise DB::select() avec des paramètres liés :
DB::select('SELECT * FROM posts WHERE category = ?', [$category]);
Jamais de concaténation de variables dans une requête SQL. Jamais.
Rate limiting
Pour les routes sensibles (connexion, formulaire de contact, réinitialisation de mot de passe), j'applique un rate limiting : un nombre maximum de tentatives par intervalle de temps, par IP. Laravel fournit le middleware throttle et la façade RateLimiter pour ça.
Sur le formulaire de contact de vs81.fr : 5 soumissions par heure par IP. C'est suffisant pour un usage légitime, et bloquant pour un script de spam automatisé.
Headers HTTP de sécurité
Via le fichier .htaccess Apache sur o2switch, j'ajoute quelques headers HTTP essentiels sur chaque réponse :
X-Frame-Options: SAMEORIGIN
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
X-Frame-Options: SAMEORIGIN empêche le clickjacking en interdisant d'intégrer le site dans une iframe externe. X-Content-Type-Options: nosniff empêche le navigateur de deviner le type MIME d'une ressource.
Pour les projets qui le nécessitent, j'ajoute une Content Security Policy (CSP) définissant explicitement les sources autorisées pour les scripts, les styles et les images.
Le .env hors du webroot
Le fichier .env contient les credentials de base de données, les clés d'API, les secrets d'application. Il ne doit jamais être accessible publiquement via HTTP.
Dans une installation Laravel standard, le webroot est le dossier public/. Le fichier .env est à la racine du projet, un niveau au-dessus : il n'est donc jamais servi directement par Apache. Sur o2switch, je vérifie systématiquement cette configuration après chaque déploiement.
Et le .env n'est jamais versionné dans Git. Le .gitignore de Laravel l'exclut par défaut : je ne touche pas à ça.
La sécurité comme habitude, pas comme checklist
Ces mesures ne sont pas exhaustives : la sécurité est un domaine qui évolue. Mais elles couvrent les vecteurs d'attaque les plus fréquents sur des projets Laravel de taille moyenne. L'objectif n'est pas la perfection théorique : c'est de ne jamais livrer un projet avec des vulnérabilités élémentaires qui auraient pu être évitées par réflexe.