ConseilsDéveloppement web

Sécuriser une application contre les attaques XSS, CSRF et SQLi

Sécuriser une application contre les attaques XSS, CSRF et SQLi

Les attaques XSS, CSRF et SQLi restent parmi les vecteurs d’attaque les plus fréquents sur les applications web. Si vous développez une application qui traite des données utilisateur, vous y serez confronté tôt ou tard.

Comprendre les attaques XSS

Le Cross-Site Scripting (XSS) permet à un attaquant d’injecter du code JavaScript malveillant dans une page web consultée par d’autres utilisateurs. Le navigateur de la victime exécute ce script sans broncher : pour lui, c’est du code légitime provenant du site.

Attaque XSS stocké

On distingue trois types de XSS : stocké, réfléchi et basé sur le DOM. Le XSS stocké est le plus problématique. Le script malveillant est enregistré en base de données (via un commentaire de forum, un champ de profil...) et s’exécute ensuite chez tous les utilisateurs qui affichent cette donnée. Un seul message piégé sur un forum peut toucher des milliers de visiteurs.

Attaque XSS réfléchie

Le XSS réfléchi fonctionne différemment : le script malveillant est inclus dans une URL et exécuté immédiatement quand la victime clique dessus. C’est le scénario classique du lien de phishing envoyé par e-mail.

Attaque XSS basée sur le DOM

Le XSS basé sur le DOM (Document Object Model) se produit entièrement côté client. Pas besoin d’interaction avec le serveur : le script manipule directement le DOM de la page via des failles dans le code JavaScript front-end.

Les trois variantes exploitent le même principe : le navigateur fait confiance au code JavaScript qui s’exécute dans le contexte d’une page. Si du code malveillant s’y glisse, le navigateur l’exécute comme le reste.

Prévenir les attaques XSS

Assainir et échapper les données saisies

Règle de base : ne jamais faire confiance aux données saisies par un utilisateur. Toute entrée doit être assainie (on supprime les éléments dangereux) et échappée (on convertit les caractères spéciaux en entités inoffensives avant l’affichage). Un <script> saisi dans un formulaire doit s’afficher comme du texte, pas s’exécuter.

Mettre en place une Content Security Policy

La Content Security Policy (CSP) est un en-tête HTTP qui restreint les ressources que le navigateur peut charger sur une page. Concrètement, elle permet de définir une liste blanche de sources autorisées pour les scripts, les styles, les images, etc. Un script injecté qui ne provient pas d’une source autorisée sera bloqué. C’est une protection supplémentaire qui limite la surface d’attaque.

Comprendre les attaques CSRF

Le Cross-Site Request Forgery (CSRF) exploite le fait que votre navigateur envoie automatiquement les cookies de session avec chaque requête vers un site sur lequel vous êtes connecté.

Le scénario type : vous êtes connecté à votre banque en ligne. Vous visitez un autre site, piégé par un attaquant. Ce site déclenche en arrière-plan une requête de virement vers le site de votre banque. Votre navigateur l’envoie avec votre cookie de session, comme si c’était vous qui aviez initié le virement. La banque reçoit une requête authentifiée et l’exécute.

Le problème de fond : le serveur ne peut pas distinguer une requête légitime d’une requête forgée tant qu’il se base uniquement sur les cookies pour l’authentification. Toute action sensible (modification de profil, transaction, changement de mot de passe) devient exploitable.

Prévenir les attaques CSRF

Les tokens anti-CSRF

Le mécanisme de défense le plus répandu est le token anti-CSRF. Le principe : le serveur génère un jeton unique lié à la session de l’utilisateur et l’inclut dans chaque formulaire (en champ caché) ou dans les headers des requêtes AJAX. À la réception de la requête, le serveur vérifie que le jeton correspond. S’il est absent ou incorrect, la requête est rejetée.

Django intègre ce mécanisme nativement via son middleware CSRF, ce qui simplifie sa mise en place.

Les headers HTTP

L’attribut SameSite sur les cookies de session est un complément efficace. En le configurant à Strict ou Lax, le navigateur n’enverra pas les cookies lors de requêtes provenant d’un autre site. Ça coupe court à la plupart des scénarios CSRF.

Restreindre les méthodes HTTP

Les actions qui modifient des données ne doivent jamais passer par des requêtes GET. Un GET peut être déclenché par une simple image ou un lien. Réservez les modifications d’état aux méthodes POST, PATCH ou DELETE, qui nécessitent une intention explicite de l’utilisateur.

Comprendre les attaques SQLi

L’injection SQL permet à un attaquant d’insérer du code SQL dans les champs de saisie d’une application pour manipuler les requêtes envoyées à la base de données. Les conséquences possibles : lecture de données confidentielles, modification d’enregistrements, suppression de tables, voire prise de contrôle complète de la base.

Injection de fragment SQL

L’exemple classique : entrer ’ OR ‘1’=’1 dans un champ de connexion. Si l’application concatène cette entrée directement dans sa requête SQL, la condition devient toujours vraie et l’attaquant accède au compte sans mot de passe.

Injection basée sur des erreurs

Il existe plusieurs variantes. Les injections basées sur les erreurs exploitent les messages d’erreur SQL pour déduire la structure de la base. Les injections à l’aveugle (blind SQLi) observent le comportement de l’application (temps de réponse, contenu de la réponse selon une condition) pour extraire de l’information bit par bit, même sans message d’erreur visible.

Prévenir les attaques SQLi

Utiliser des prepared statements

Les requêtes paramétrées (prepared statements) séparent le code SQL des données utilisateur. Au lieu de concaténer les entrées dans la requête, elles les passent comme des paramètres typés. Le moteur SQL ne les interprétera jamais comme du code. C’est la mesure la plus directe contre les SQLi.

Adopter un ORM

Les ORM (Object-Relational Mapping) ajoutent une couche d’abstraction entre le code applicatif et la base de données. Les développeurs manipulent des objets plutôt que des requêtes SQL brutes, ce qui réduit mécaniquement le risque d’injection. Attention toutefois : certains ORM permettent d’écrire des requêtes brutes, et ces cas restent vulnérables si les entrées ne sont pas paramétrées.

Valider les données des entrées

Toute donnée reçue d’un utilisateur doit être validée avant d’être utilisée. Un champ qui attend un entier ne doit accepter qu’un entier. Un e-mail doit respecter un format d’e-mail. Cette validation doit être présente côté client (pour l’expérience utilisateur) et côté serveur (pour la sécurité, car la validation côté client est contournable).

Restreindre les permissions

Le compte de base de données utilisé par l’application doit avoir les permissions minimales nécessaires. Si l’application n’a besoin que de lire et d’écrire dans certaines tables, inutile de lui donner les droits de suppression ou d’administration. En cas d’injection réussie, les dégâts restent limités au périmètre autorisé.

XSS, CSRF, SQLi : ces trois familles d’attaques sont connues depuis des années, bien documentées, et pourtant on les retrouve régulièrement dans des audits de sécurité. Les protections existent et ne sont pas compliquées à mettre en place. Ce qui manque souvent, c’est de les intégrer dès le début du projet plutôt qu’en réaction à un incident.

Envie de vous lancer ?

Du cadrage au prototype, jusqu'à l'intégration IA.

Nous accompagnons vos projets de logiciels métier de bout en bout.

Développer mon projet