Comment protéger les applications Node.js contre les attaques CSRF
Victor Ikechukwu
17 octobre 2023
0 minutes de lectureUne attaque par falsification de requête intersites (CSRF) est une faille de sécurité qui exploite la relation de confiance entre un navigateur web et un site légitime. Des attaquants malveillants manipulent les navigateurs pour leur faire exécuter des actions malveillantes sur des sites où les utilisateurs s’authentifient et se connectent. Souvent, ces attaques commencent lorsque les utilisateurs cliquent sur un lien contenu dans un e-mail trompeur ou arrivent sur un site compromis, sans se douter du code qui s’exécute en arrière-plan.
Les conséquences d’une attaque CSRF réussie peuvent aller des pertes financières et de l’atteinte à la réputation, pour les particuliers comme pour les entreprises, à la compromission de comptes utilisateurs, aux transactions non autorisées et même à des responsabilités juridiques. À mesure que les attaques CSRF évoluent et gagnent en sophistication, les développeurs web et les organisations doivent mettre en place des contre-mesures robustes pour préserver l’intégrité de leurs applications web.
Cet article explique le fonctionnement des attaques CSRF dans les applications Node.js et comment s’en protéger. Nous examinerons des exemples concrets, accompagnés d’étapes pratiques et d’extraits de code, des méthodes pour tester les protections et des bonnes pratiques pour sécuriser les applications Node.js contre les attaques CSRF.
Nous proposons également une leçon pratique gratuite sur les attaques CSRF sur Snyk Learn, si vous souhaitez vous lancer directement.
Comprendre les attaques CSRF
Les attaques CSRF exploitent la confiance que les applications web accordent aux sessions des utilisateurs authentifiés. En incitant les utilisateurs à effectuer des actions involontaires, les attaquants peuvent manipuler ou divulguer des données sensibles à leur insu. Avant d’apprendre à protéger les applications Node.js contre ces menaces, examinons le fonctionnement de ces attaques et leurs conséquences potentielles.
Lorsqu’un utilisateur se connecte à un site, il le reste pendant une période donnée — de quelques jours à plusieurs mois — avant de devoir s’authentifier à nouveau. Cette période d’authentification s’appelle une session. Pendant une session active, le serveur crée un identifiant ou jeton unique aléatoire — un ID de session — et l’associe à cette session. Le serveur renvoie ensuite l’ID de session à l’utilisateur, qui est stocké dans les cookies du navigateur (des données associées au navigateur de l’utilisateur pendant une session).
Dès lors, chaque fois que l’utilisateur envoie une requête qui modifie l’état du site (par exemple, en envoyant un formulaire), l’ID de session accompagne la requête. Le serveur compare cet ID au jeton qu’il détient. Si les valeurs correspondent, il autorise la requête et l’application exécute l’action. Sinon, il révoque l’accès.
Dans une attaque CSRF classique, les attaquants exploitent la confiance accordée aux sessions authentifiées en élaborant des requêtes malveillantes qui imitent une action effectuée au nom d’une victime connectée. Les acteurs malveillants peuvent mener à bien des attaques CSRF grâce à des techniques d’ingénierie sociale, par exemple en intégrant des liens nuisibles dans des e-mails ou sur des sites fréquentés par les utilisateurs ciblés. Les applications web insuffisamment sécurisées risquent d’autoriser par inadvertance ces requêtes en tant qu’actions légitimes, car elles comportent des identifiants valides.
Les enjeux des attaques CSRF sont considérables. Par exemple, la faille de sécurité de Facebook en 2018 a touché plus de 50 millions de comptes dans le monde. En cause ? Des jetons d’accès insuffisamment protégés, susceptibles d’être détournés entre différentes origines pour authentifier les requêtes côté client. Cette protection insuffisante a compromis des données sensibles d’utilisateurs et entraîné des pertes financières, une atteinte à la réputation et des conséquences juridiques. Une faille de sécurité peut faire perdre la confiance des clients et nuire à la réputation d’une organisation et de ses services.
Les conséquences d’une attaque CSRF réussie varient selon l’application ciblée et les fonctionnalités qu’elle met à la disposition de l’utilisateur. Parmi les effets possibles d’une attaque CSRF réussie :
Manipulation des données — Les attaques CSRF peuvent permettre aux attaquants de manipuler des données sensibles dans une application web. Il peut s’agir de modifier les paramètres du profil d’un utilisateur, ses préférences et paramètres de compte, ou de falsifier les données qu’il peut modifier selon ses droits d’accès.
Actions non autorisées — Un attaquant peut forger des requêtes pour exécuter des actions que l’utilisateur authentifié n’a pas autorisées. Il peut, par exemple, envoyer des formulaires, effectuer des transactions financières ou supprimer du contenu.
Divulgation d’informations — Les attaquants peuvent exploiter des failles pour inciter les utilisateurs à révéler des données confidentielles, telles que des messages privés ou des informations financières. Ils peuvent également les amener à divulguer des données propriétaires stockées dans l’application.
Prise de contrôle de compte — En incitant les utilisateurs à modifier les identifiants de leur compte, par exemple leurs informations de connexion, les attaquants peuvent obtenir un accès non autorisé et prendre le contrôle des comptes compromis. Ils peuvent alors usurper l’identité de l’utilisateur légitime, accéder à des ressources restreintes et éventuellement lancer d’autres attaques dans l’application ou contre d’autres utilisateurs.
Stratégies de protection contre les attaques CSRF
Voici les principales techniques pour protéger les applications Node.js contre les attaques CSRF :
Utiliser le modèle du jeton synchronisé (STP)
Le modèle du jeton synchronisé consiste à générer un jeton unique pour chaque session utilisateur. Celui-ci est intégré aux formulaires ou transmis dans une requête AJAX, sous forme de valeur d’en-tête personnalisée ou de partie d’une charge utile JSON. À la réception des requêtes, le serveur valide ce jeton.
Le STP génère un jeton aléatoire unique pour chaque session utilisateur : un jeton CSRF. Le serveur envoie ce jeton à l’utilisateur dans la charge utile de la réponse, par exemple une réponse HTML ou JSON. L’application inclut le jeton dans les en-têtes de requête ou sous forme de paramètre POST personnalisé dans chaque requête suivante. Le serveur vérifie ensuite que le jeton reçu existe et correspond à celui de la session utilisateur. Si c’est le cas, la requête provient d’un utilisateur légitime disposant d’une session valide.
Le STP est facile à mettre en œuvre et protège efficacement contre les vecteurs d’attaque courants. Il peut toutefois nécessiter une gestion supplémentaire de l’état côté serveur. Si vous stockez les jetons CSRF dans des cookies avec le STP, ajoutez le préfixe __Host- afin de renforcer la sécurité des cookies et de les rendre inaccessibles depuis les domaines autres que celui sur lequel ils ont été définis.
Configurer des cookies SameSite
La stratégie des cookies SameSite consiste à définir un attribut SameSite sur les cookies de session, afin que l’application ne les envoie qu’avec les requêtes provenant du même domaine que le site cible. Cette méthode empêche les requêtes d’inclure des cookies inter-origines. L’attribut SameSite accepte deux valeurs : strict et lax.
Avec la valeur strict, le navigateur n’envoie les cookies de session que dans un contexte de première partie : il ne les envoie pas lorsque l’utilisateur accède à un autre site web. Cette méthode empêche efficacement les attaques CSRF provenant de sites tiers malveillants.
Avec la valeur lax, le navigateur envoie le cookie avec les requêtes provenant du même site (domaine) que celui qui l’a défini, ainsi qu’avec les requêtes GET de premier niveau.
Même si les navigateurs modernes appliquent automatiquement les attributs de cookie SameSite, les anciens navigateurs et les clients non web, comme les applications mobiles, ne les prennent en charge que de façon limitée. Cela réduit considérablement l’efficacité des cookies SameSite contre les attaques CSRF. Les développeurs doivent donc envisager d’autres stratégies de protection contre les attaques CSRF et garantir une protection complète sur un large éventail d’environnements clients.
Utiliser le modèle Double Submit Cookie
Le modèle Double Submit Cookie ajoute un cookie supplémentaire contenant un jeton unique aux identifiants de session habituels. Lors de l’envoi, ce cookie est joint aux en-têtes de requête côté client ou aux données du formulaire. Le modèle Double Submit Cookie réduit la charge liée à la gestion de l’état sans nuire sensiblement aux performances globales. Il est donc idéal pour les applications sans état qui s’appuient sur des réseaux de distribution de contenu divers ou des architectures de microservices.
Cette méthode ne protège toutefois pas contre les attaques avancées ciblant les mécanismes de stockage du navigateur qui contiennent des jetons secondaires. Le cross-site scripting (XSS) est l’un de ces vecteurs d’attaque. Les applications vulnérables aux attaques XSS peuvent permettre à un attaquant de récupérer le jeton unique dans un cookie et de l’utiliser dans des requêtes malveillantes ultérieures.
En outre, le modèle Double Submit Cookie est vulnérable aux attaques de l’intercepteur (MITM) si les utilisateurs n’appliquent pas les mesures de sécurité appropriées. L’attaquant peut intercepter le jeton CSRF d’origine dans la requête initiale du client et l’utiliser pour créer des requêtes malveillantes.
Vous pouvez utiliser des cookies à double soumission signés pour renforcer le modèle Double Submit Cookie. Cette stratégie repose sur une clé secrète connue du serveur seul, ce qui empêche un attaquant de générer et d’insérer son propre jeton CSRF.
Parmi les autres mesures de renforcement, citons l’application de l’en-tête de réponse HTTP Strict-Transport-Security (HSTS) et l’utilisation de préfixes de cookie, tels que __Host-. Toutefois, au moment de la rédaction de cet article, 25 % des navigateurs ne prennent pas en charge les préfixes de cookie.
Mettre en œuvre la protection contre les attaques CSRF dans une application Node.js
Maintenant que nous avons examiné les stratégies de sécurisation de nos applications contre les attaques CSRF, voyons comment les mettre en œuvre. Pour suivre ce guide, assurez-vous de disposer des éléments suivants :
Node.js installé sur votre ordinateur.
Un éditeur de code. Ce guide utilise Visual Studio (VS) Code
Un navigateur web
Un compte Snyk gratuit, l’interface de ligne de commande (CLI) Snyk Code et l’extension Snyk pour VS Code
Nous allons créer une application Node.js simple qui permet aux utilisateurs de transférer des fonds à d’autres utilisateurs. Elle utilisera le framework web Express.
Commencez par créer un dossier pour le projet et nommez-le nodejs-csrf-strategies. Ouvrez ce dossier dans un terminal et exécutez la commande npm init -y pour initialiser un projet Node.js. Exécutez ensuite la commande npm i express pour installer le framework web Express.
Créez un fichier nommé index.js et collez-y le code ci-dessous.
Dans cet exemple d’application, une route / affiche le formulaire HTML qui recueille le montant à transférer. Ensuite, la route /transfer renvoie un message indiquant que le montant saisi dans le formulaire a bien été transféré. Dans une application réelle, la logique de transfert serait implémentée ici. Notez que le code utilisé dans cette application est vulnérable aux attaques CSRF — ne l’utilisez pas en production.
Après avoir installé la Snyk CLI sur votre ordinateur, activez Snyk Code et analysez le projet d’exemple pour détecter les failles. La Snyk CLI vous permet d’intégrer les fonctionnalités de Snyk Code à votre workflow de développement et d’exécuter des tests Snyk Code en local pour détecter les failles de sécurité dans votre code.
Pour ce faire, ouvrez le dossier du projet dans le terminal. Exécutez la commande snyk code test. Vous devriez obtenir un résultat semblable à la capture d’écran ci-dessous, avec des détails sur la transmission de données sensibles en texte clair, l’utilisation d’un hachage de mot de passe nécessitant trop peu de calculs, l’exposition d’informations, les attaques CSRF, le déni de service par expression régulière (ReDoS) et les attaques XSS.

Ce résultat indique que l’application est vulnérable aux attaques CSRF et aux autres failles répertoriées.
Survolez la ligne qui initialise l’application Express — const app = express() — pour consulter les informations détaillées de Snyk sur les attaques CSRF et les bonnes pratiques pour les prévenir, comme dans la capture d’écran ci-dessous. Cette détection des failles en temps réel est rendue possible par l’extension Snyk pour VS Code, qui vous aide à repérer les failles au fur et à mesure que vous écrivez votre code.

Maintenant que Snyk Code a détecté la vulnérabilité de notre application Node.js aux attaques CSRF, voyons comment les mesures de protection mentionnées peuvent nous aider.
Protéger notre application avec le STP
Mettons en œuvre le STP dans l’application Node.js d’exemple. Commencez par installer le middleware csurf avec la commande `npm install csurf`. Ce middleware nécessite l’initialisation d’un middleware de session ou d’un analyseur de cookies. Dans cet exemple, nous utiliserons l’analyseur de cookies.
Installez un analyseur de cookies en exécutant la commande npm install cookie-parser.
Ensuite, importez le middleware et l’analyseur de cookies au début de votre fichier JavaScript.
Activez l’analyse des cookies et configurez le middleware de route en ajoutant le code suivant juste avant la route GET.
Nous devons analyser les cookies, car l’option de cookie est définie sur true dans csrfProtection.
Ajoutez maintenant le jeton CSRF généré dans un champ de saisie masqué lors de l’affichage du formulaire HTML. Cette opération ajoute le jeton CSRF au formulaire HTML qui sera envoyé. Remplacez le code de la route GET par le code suivant.
Modifiez la route POST avec le code ci-dessous pour appliquer le middleware csrfProtection.
Ce middleware vérifie les requêtes POST reçues en comparant la valeur du champ _csrf envoyée par l’application dans le corps de la requête au jeton CSRF stocké dans la session de l’utilisateur. Ce dernier est associé à ses cookies.
Protéger notre application à l’aide des cookies SameSite
Mettons en œuvre les cookies SameSite dans l’application Node.js créée précédemment. Commencez par installer le middleware cookie-parser en exécutant npm install cookie-parser. Importez le middleware cookie-parser dans l’application et initialisez-le à l’aide d’une clé secrète, comme indiqué ci-dessous.
La valeur de <your-secret-key> doit être une chaîne de caractères unique servant à signer les cookies : une valeur aléatoire, longue et imprévisible, générée à l’aide d’une méthode cryptographiquement sécurisée.
La signature d’un cookie à l’aide de cette chaîne unique hache son contenu et crée une signature unique. Lorsque le serveur reçoit ultérieurement le cookie du navigateur, il peut en vérifier l’intégrité en contrôlant sa signature avec la même clé secrète unique.
Cette méthode est utile contre le détournement de session, lorsqu’un attaquant tente de voler ou d’usurper la session d’un utilisateur. Si un attaquant modifie le cookie, sa signature ne correspond plus et le serveur détecte qu’il a été altéré. Les attaquants ne peuvent donc pas modifier les données de session stockées dans les cookies.
Protéger notre application à l’aide du modèle Double Submit Cookie
Pour mettre en œuvre le modèle Double Submit Cookie, installez cookie-parser. Ajoutez ensuite le code suivant à l’application pour importer les packages requis et activer l’analyse des cookies.
Créez maintenant des fonctions middleware pour générer et valider des jetons CSRF à l’aide du code ci-dessous.
Appliquez ensuite le middleware generateCSRFToken à la route GET.
Enfin, appliquez la fonction middleware validateCSRFToken à la route POST.
Tester la protection contre les CSRF
Il est essentiel de tester la protection contre les CSRF pour :
Empêcher les actions non autorisées — Vous pouvez vérifier que l’application Node.js et les autres stratégies mises en œuvre valident correctement les requêtes afin d’empêcher les actions non autorisées.
Protéger les données personnelles et la vie privée — Vous pouvez vous assurer que les données des utilisateurs restent sécurisées et protégées contre les attaques CSRF visant à exposer ou à manipuler des données sensibles.
Respecter les normes de sécurité — De nombreuses normes et réglementations de sécurité, comme la norme de sécurité des données de l’industrie des cartes de paiement (PCI DSS), exigent des organisations qu’elles mettent en place une protection contre les CSRF. Tester cette protection permet de garantir la conformité à ces normes et d’éviter des pénalités ou des problèmes juridiques.
Détecter les vulnérabilités — En simulant des attaques et en testant la robustesse des mesures de sécurité contre les CSRF, vous pouvez détecter et corriger les vulnérabilités avant qu’elles ne soient exploitées par des personnes malveillantes.
Nous pouvons utiliser un formulaire HTML personnalisé pour simuler une attaque CSRF sur le code index.js d’origine, non modifié, présenté au début de ce tutoriel. Voici un exemple de formulaire HTML.
Ce formulaire HTML personnalisé affiche un message alléchant à l’utilisateur. Il lui annonce qu’il a gagné 100 $ et l’invite à réclamer son prix en cliquant sur le bouton. En parallèle, un formulaire masqué envoie le montant au point de terminaison /transfer à son insu. Le code de la balise <script> du formulaire HTML envoie automatiquement le formulaire au chargement de la page. Avec le code d’origine, le transfert aboutirait, car le serveur ne pourrait pas détecter la menace CSRF.
Pour tester l’une des stratégies de protection contre les CSRF mises en œuvre, lancez le serveur après avoir appliqué la stratégie STP. Essayez ensuite d’envoyer le formulaire HTML personnalisé. Le serveur renverra l’erreur ForbiddenError: invalid csrf token et le transfert ne sera pas traité. Ce résultat montre que la stratégie de protection contre les CSRF fonctionne comme prévu.
Pour tester chaque stratégie mise en œuvre :
STP — Créez une requête sans jeton valide ou avec un jeton expiré. Vérifiez si le serveur la rejette.
Cookies SameSite — Effectuez des requêtes inter-origines depuis différents domaines. Vérifiez si les serveurs refusent les accès non autorisés en l’absence de cookies de session.
Double Submit Cookies — Envoyez une requête contenant des jetons différents dans les données envoyées ou les en-têtes et dans les cookies de session, afin de vérifier que les serveurs les valident correctement.
Utilisez maintenant Snyk pour rechercher des vulnérabilités dans le code mis à jour. Vous pouvez tester le code avec les autres stratégies, mais pour cette démonstration, nous nous concentrerons sur celui qui met en œuvre la stratégie STP.
Exécutez la commande snyk code test pour rechercher des vulnérabilités. Vous devriez obtenir un résultat semblable à la capture d’écran suivante.

Les résultats montrent que le code présente des vulnérabilités liées à l’exposition d’informations et aux attaques XSS, mais aucune vulnérabilité CSRF. Cela signifie que nous avons corrigé la vulnérabilité CSRF détectée précédemment.
Bonnes pratiques de protection contre les CSRF dans les applications Node.js
En plus de mettre en œuvre les stratégies ci-dessus, renforcez la protection contre les CSRF en suivant ces bonnes pratiques :
Mettez régulièrement à jour les dépendances et les middlewares pour maintenir des configurations de sécurité à jour. Des outils comme Snyk Open Source simplifient ce processus en détectant les composants obsolètes et en suggérant des correctifs.
Mettez en œuvre une politique de sécurité du contenu (CSP) qui limite les requêtes aux sources de confiance et réduit ainsi les vecteurs d’attaque potentiels.
Combinez plusieurs techniques de protection contre les CSRF, comme le STP avec les cookies SameSite, ou associez Double Submit Cookies à l’application de la CSP. Cette approche à plusieurs niveaux limite les vulnérabilités liées à l’utilisation d’une seule stratégie.
Étapes suivantes
Il est essentiel de comprendre les attaques CSRF et leurs conséquences pour sécuriser les applications Node.js. La mise en œuvre de stratégies de protection robustes, leur test efficace et le respect des bonnes pratiques renforcent les défenses de l’application contre les menaces.
Tester régulièrement les vulnérabilités, comme les CSRF, et mettre en œuvre des mécanismes de sécurité robustes permet d’atténuer les risques et d’empêcher les actions non autorisées. Adoptez des mesures de sécurité proactives et des techniques à jour pour développer des applications Node.js sécurisées, en corrigeant les vulnérabilités avant qu’elles ne soient exploitées par des acteurs malveillants.
Pour sécuriser vos applications Node.js, mettez en pratique les concepts et stratégies abordés dans cet article et essayez Snyk Code.
Lancez-vous dans les compétitions Capture The Flag
Apprenez à résoudre des défis Capture The Flag en regardant à la demande notre atelier virtuel d’initiation.
