Pourquoi êtes-vous ici ?
Vous avez déjà entendu parler des attaques par injection SQL de JavaScript, mais vous ne savez pas exactement à quoi elles ressemblent dans la nature ni si vous devez vous en préoccuper. Vous essayez peut-être de comprendre à quel point cela peut être grave.
En bref, si vous créez des applications utilisant des bases de données SQL, telles que MySQL et PostgreSQL, vous courez un risque : vous n'êtes pas à l'abri des méthodes d'attaque qui touchent les développeurs et leurs bases de données depuis des dizaines d'années. En tant que développeur, il vous incombe de mettre en place des garde-fous qui protègent les données des utilisateurs et garantissent que votre infrastructure sous-jacente ne fait jamais l'objet d'une intrusion, d'une exploration ou d'une réquisition.
Tous les nouveaux outils prétendent vous aider, mais ils ne font que rendre le développement plus complexe.
Vous pouvez ajouter un mappeur objet-relationnel (ORM) comme Sequelize et TypeORM pour simplifier la façon dont vous travaillez avec des bases de données SQL comme MySQL et PostgreSQL, mais ils ne vous exonèrent pas complètement du risque. Les pare-feu pour applications web (WAF) vous aident à bloquer les attaques au niveau du réseau, mais ils nécessitent une infrastructure coûteuse et une maintenance constante. Les scanners de code peuvent vous aider à identifier les failles évidentes, mais ils sont beaucoup moins efficaces pour les inconnues et les techniques de type "zero-day" qui se cachent.
Nous vous présenterons une image claire de ce à quoi ressemblent les attaques par injection SQL, du risque qu'elles comportent et des erreurs de développement qui les rendent possibles. Ensuite, nous vous accompagnerons dans l'installation d'un correctif global afin que vous sachiez, avec certitude, que vos applications sont sûres.
Attaques par injection SQL : exemples et implications
La définition la plus élémentaire d'une attaque par injection SQL est qu'une application permet à une entrée utilisateur non validée et non nettoyée d'exécuter des requêtes de base de données, ce qui permet à un attaquant de lire la base de données SQL, de modifier des enregistrements ou de les supprimer à sa guise.
Comme d'habitude, XKCD illustre le danger de SQL mieux que la plupart des scénarios sombres que nous pourrions imaginer :

À quoi ressemble une application JavaScript vulnérable ?
Commençons par un exemple de pseudocode simple : une application JavaScript avec un élément d'entrée qui permet aux utilisateurs de faire une recherche dans une base de données de chats. Dans l'exemple de code JavaScript ci-dessous, l'application répond aux requêtes POST sur le chemin /cats pour extraire l'entrée de l'utilisateur du corps de la requête et se connecte à la base de données avec une requête pour retourner tous les chats avec un identifiant correspondant. L'application affiche ensuite le chat à l'aide de la réponse JSON.
app.post("/cats", (request, response) => {
const query = `SELECT * FROM cats WHERE id = ${request.body.id}`;
connection.query(query, (err, rows) => {
if(err) throw err;
response.json({
data: rows
});
});
});
Bien que cet exemple puisse sembler inoffensif pour ceux qui n'ont pas été formés aux attaques par injection SQL, il est extrêmement vulnérable. Notamment, l'application ne tente pas de valider ou d'assainir l'entrée de l'utilisateur pour les chaînes de caractères ou les méthodes d'encodage potentiellement dangereuses, etconcatène l'entrée de l'utilisateur directement dans la requête SQL, ce qui donne aux attaquants de multiples occasions d'attaquer en utilisant des méthodes d'attaque par injection SQL courantes qui existent depuis des dizaines d'années.
Exemple de charges utiles d'attaque JavaScript SQL
L'injection SQL consiste à tromper votre base de données MySQL ou PostgreSQL pour qu'elle effectue une action ou réponde avec des données en dehors du cadre prévu, en raison de la manière dont votre application génère des requêtes SQL.
Le 1=1 est toujours vrai L'attaque peut retourner toute la table des chats avec des astuces comme les apostrophes ou les guillemets, parce que 1=1
est en effet toujours VRAI :
- L'utilisateur saisit les données :
BOBBY TABLES" OU 1="1
- La base de données exécute la requête SQL :
SELECT * FROM Users WHERE Cat = BOBBY TABLES OR 1=1 ;
De même, les attaquants peuvent exploiter une = est toujours vrai attaque pour renvoyer tous les chats, car ""=""
est toujours VRAI :
- L'utilisateur saisit les données :
" OR ""="
- La base de données exécute la requête SQL :
SELECT * FROM Cats WHERE CatId ="" ou ""="" ;
Les attaquants exploitent souvent la manière dont les bases de données gèrent les commentaires en ligne, et en insérant des commentaires (/* ... */)
dans une requête, ils peuvent obscurcir leur intention ou contourner les filtres.
- L'utilisateur saisit les données :
DR/*hello world*/OP/*sneak attack*/ TABLE Cats ;
- La base de données exécute la requête SQL :
DROP TABLE Cats ;
Une autre stratégie courante d'injection SQL en JavaScript est l'empilement de requêtes, qui permet aux attaquants de commencer par une chaîne inoffensive, puis d'utiliser un point-virgule ( ;) pour mettre fin à cette déclaration et en commencer une autre contenant leur injection. Les attaquants utilisent souvent l'empilement de requêtes pour supprimer des bases de données entières d'un seul coup à l'aide d'une commande DROP TABLE :
- L'utilisateur saisit les données :
Bobby ; DROP TABLE Cats --
- L'application construit sa requête SQL :
const query = "SELECT * FROM Cats WHERE CatId = " + input ;
- La base de données exécute la requête SQL :
SELECT * FROM Cats WHERE CatId = BOBBY ; DROP TABLE Cats ;
Qu'en est-il des attaques par injection NoSQL ?
Les attaques par injection NoSQL sont tout aussi dangereuses pour la sécurité de votre application et des données des utilisateurs, mais elles n'affectent que les piles technologiques utilisant des bases de données telles que MongoDB. La principale différence réside dans le style des attaques, car les requêtes SQL et NoSQL utilisent une syntaxe totalement unique qui ne se traduit pas d'une catégorie à l'autre.
Si vous utilisez une base de données SQL, vous ne risquez pas d'être victime d'une attaque par injection NoSQL, et vice versa.
Le chemin de base : corriger manuellement toutes les vulnérabilités d'injection SQL
À ce stade, vous êtes peut-être moins intéressé par la description de toutes les astuces d'injection possibles que par la manière de protéger les données que vous avez dans MySQL ou PostgreSQL.
- Utiliser des requêtes paramétrées: SQL dispose d'une fonctionnalité permettant de déconnecter l'exécution des requêtes et des valeurs, protégeant ainsi la base de données des attaques par injection.Avec l'exemple JavaScript/Node.js ci-dessus, vous pouvez employer un espace réservé dans votre requête SQL avec un point d'interrogation (
?
). Lesconnexion.query()
prend alors le paramètre en deuxième argument, ce qui donne les mêmes résultats dans une méthode à l'épreuve des injections.
app.post("/cats", (request, response) => {
const query = `SELECT * FROM Cats WHERE id = ?`;
const value = request.body.id;
connection.query(query, value, (err, rows) => {
if(err) throw err;
response.json({
data: rows
});
});
});
- Valider et assainir les entrées des utilisateurs: Si les requêtes paramétrées peuvent contribuer à protéger votre base de données SQL contre les intrusions et les attaques, vous pouvez également empêcher les utilisateurs de saisir des chaînes de caractères potentiellement dangereuses dans votre application.
Une option consiste à ajouter à votre application des bibliothèques open-source pour l'assainissement et la validation. Par exemple, vous pouvez utiliser validator.js dans l'écosystème JavaScript/Node.js pour vérifier qu'un utilisateur essaie d'entrer une véritable adresse électronique - et non une attaque par injection SQL - dans votre formulaire d'inscription.
Vous pouvez également développer des validateurs personnalisés basés sur des expressions rationnelles pour effectuer un travail similaire, mais le chemin à parcourir sera extrêmement long et complexe, avec des recherches et des tonnes de tests manuels. De plus, pouvez-vous vraiment interpréter cet exemple de regex pour la validation d'un courriel ?const re = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
La même idée s'applique pour empêcher les chaînes de caractères comme...' OR 1-'1.
Vous pouvez essayer de rechercher et de fermer toutes ces opportunités vous-même, mais vous préférerez probablement passer votre temps à créer de nouvelles fonctionnalités.
- Déployer des WAF ou des plateformes de sécurité basées sur des agents: Bien que ces solutions puissent bloquer les attaques SQL avant même qu'elles ne touchent votre application, ou au moins vous avertir en temps réel lorsque des attaques se produisent, elles sont assorties de quelques mises en garde.
Tout d'abord, elles sont souvent coûteuses et vous obligent à lancer une nouvelle infrastructure sur site ou dans le nuage, ce qui est souvent beaucoup plus complexe que ce que vous avez signé en tant que développeur qui veut juste expédier à la production. Deuxièmement, elles nécessitent davantage de maintenance manuelle pour mettre à jour le jeu de règles, ce qui vous empêche d'effectuer d'autres interventions manuelles en cas d'injection de code SQL. Enfin, ils ajoutent souvent une charge de calcul supplémentaire ou redirigent toutes les requêtes via leur plateforme d'analyse, ce qui augmente la latence et nuit à l'expérience de l'utilisateur final.
Le gros problème est que les possibilités d'attaques par injection SQL sont comme des mauvaises herbes - vous pouvez les couper une fois à l'aide de ces outils, mais vous devez être constamment vigilant sur l'ensemble de votre base de code pour vous assurer qu'elles ne repoussent jamais.
Une voie alternative pour résoudre les attaques JavaScript par injection SQL : Pare-feu Aikido
Aikido Security a récemment publié Firewall, un moteur de sécurité gratuit et open-source qui vous protège de manière autonome contre les attaques par injection SQL et bien d'autres choses encore.
Si vous n'utilisez pas Node.js, sachez que nous prendrons en charge d'autres langages et frameworks à l'avenir. Vous pouvez toujours vous abonner à notre bulletin d'information sur les produits pour savoir exactement quand Firewall s'étendra au-delà du monde JavaScript ou nous envoyer un courriel à hello@aikido.dev si vous souhaitez parler d'un langage spécifique.
Tester une application vulnérable à l'injection SQL JavaScipt
Nous allons utiliser un exemple d'application fourni avec le dépôt open-source pour montrer comment fonctionne Aikido Firewall. Vous aurez également besoin de Docker/DockerCompose pour déployer une base de données MySQL locale.
Commencez par forker le dépôt firewall-node et clonez ce fork sur votre station de travail locale.
git clone https://github.com/<YOUR-GITHUB-USERNAME>/firewall-node.gitcd firewall-node
Utilisez Docker pour déployer une base de données MySQL locale sur le port 27015. Ce fichier docker-compose.yml crée également des conteneurs s3mock, MongoDB et PostgreSQL, car il a été créé pour aider l'équipe d'Aikido à tester la façon dont Firewall bloque diverses attaques.
docker-compose -f sample-apps/docker-compose.yml up -d
Lancez ensuite l'application modèle :
node sample-apps/express-mysql2/app.js
Ouvrir http://localhost:4000
dans votre navigateur pour découvrir cette application très simple. Dans la zone de texte, tapez quelques noms de chats et cliquez sur le bouton Ajouter pour tester l'injection d'un code SQL. Pour tester l'injection SQL, vous pouvez soit cliquer sur le bouton Injection de test ou tapez le texte suivant dans la zone de texte : Kitty') ; DELETE FROM cats;-- H
et cliquez sur Ajouter à nouveau. Quoi qu'il en soit, l'application vous permet d'empiler plusieurs requêtes à l'aide de commentaires sournois, supprimant ainsi la totalité de la base de données des chats.
Comment cela se passe-t-il ? Comme nous l'avons déjà signalé, cette application ajoute simplement tous l'entrée de l'utilisateur à la fin de la requête SQL, ce qui n'est pas sûr par nature.
const query = `INSERT INTO cats(petname) VALUES ('${name}');`
Les conséquences peuvent être minimes, mais il n'est pas difficile d'imaginer comment cette erreur souvent honnête peut avoir des conséquences désastreuses pour votre application de production.
Blocage de l'injection JavaScript SQL avec Aikido Firewall
Voyons maintenant avec quelle rapidité notre moteur de sécurité open-source bloque les attaques JavaScript par injection SQL sans avoir à corriger manuellement chaque interaction avec la base de données dans votre code.
Si vous n'avez pas encore de compte Aikido, n'hésitez pas à en créer un. en faire un gratuitement. Si vous en avez déjà un, connectez-vous et connectez votre compte GitHub. Au cours de ce processus, accordez à l'Aikido l'accès à la lecture de votre fourche de l'accord. nœud de pare-feu
projet.
Aller à la page Tableau de bord du pare-feu et cliquez sur Ajouter un service. Donnez un nom à votre service et choisissez à nouveau votre fourchette pour le service nœud de pare-feu
projet.

Aikido vous explique ensuite comment installer et mettre en œuvre Aikido Firewall. Comme nous utilisons l'application d'exemple, ce travail est déjà fait pour vous, mais il s'agit d'une référence utile sur la façon d'apporter notre moteur de sécurité open-source à toutes vos applications Node.js qui pourraient être vulnérables à des attaques JavaScript par injection SQL.

Cliquez sur le bouton Générer un jeton pour créer un jeton permettant à Aikido Firewall de transmettre en toute sécurité les informations sur les attaques par injection SQL bloquées à la plateforme de sécurité Aikido. Copiez le jeton généré, qui commence par AIK_RUNTIME...
et retournez à votre terminal pour réexécuter l'exemple d'application, mais maintenant avec le Pare-feu entièrement activé en mode blocage :
AIKIDO_TOKEN=<YOUR-AIKIDO-TOKEN> AIKIDO_DEBUG=true AIKIDO_BLOCKING=true node sample-apps/express-mysql2/app.js
Ouvrir localhost:4000
et invoque à nouveau l'attaque par injection SQL incluse. Cette fois, Aikido vous bloquera au niveau du navigateur, enverra un message dans les journaux de votre serveur web local et générera un nouvel événement. Cliquez sur cet événement pour obtenir des détails complets sur la tentative d'injection SQL, y compris la charge utile et l'endroit où votre application a généré la dangereuse requête SQL.

Au lieu de s'inquiéter de la protection permanente de vos applications contre les attaques par injection JavaScript SQL, qu'elles soient critiques ou non, Aikido Firewall offre un blocage complet et une observabilité sophistiquée qui vous tient informé des sources d'attaque, des charges utiles courantes et des points faibles potentiels.
Quelle est la prochaine étape ?
Vous pouvez installer et mettre en œuvre Aikido Firewall dans toutes vos applications basées sur Node.js gratuitement. Notre moteur de sécurité embarqué open-source protège votre infrastructure et les données de vos utilisateurs contre les attaques JavaScript SQL injection, l'injection de commandes, la pollution des prototypes, la traversée de chemin, et bien d'autres encore à venir prochainement.
Nous ne disons pas que Firewall devrait remplacer les meilleures pratiques de développement pour se protéger contre les injections SQL, comme l'utilisation de requêtes paramétrées ou le fait de ne jamais faire confiance à la saisie de l'utilisateur, mais nous savons aussi, par expérience personnelle, qu'aucun développeur n'est parfait. Aucune base de code n'est sans faille, et des erreurs honnêtes se produisent tout le temps.
Considérez Firewall comme un correctif global pour l'injection SQL. Contrairement aux expressions rationnelles développées sur mesure, aux WAFs induisant une latence ou aux agents de sécurité complexes qui coûtent une fortune, Firewall fait ce travail extraordinairement bien et avec un impact négligeable, et ce, tout à fait gratuitement.
Si vous aimez ce que vous avez vu, consultez notre feuille de route et donnez une étoile à notre dépôt GitHub(https://github.com/AikidoSec/firewall-node). ⭐