Bonjour, Habr! Cet article intéressera ceux qui utilisent déjà la bibliothèque Sequelize ou qui vont simplement travailler avec. Sous la coupe, nous vous dirons comment la fonctionnalité intégrée operatorAliases peut être nuisible et comment éviter une fuite de votre propre base de données.
Qu'est-ce que Sequelize, où est-il utilisé et dans quel but?
Sequelize est une bibliothèque ORM Node.js pour Postgres, MySQL, MariaDB, SQLite et Microsoft SQL Server qui mappe les tables dans les bases de données et leurs relations avec les classes. Lors de l'utilisation de Sequelize, nous n'avons pas à écrire de requêtes SQL, mais nous devons travailler avec des données comme avec des objets ordinaires. Il offre une prise en charge transactionnelle robuste, des relations, un chargement actif et différé, une réplication en lecture, etc.
Qu'est-ce que operatorAliases et quel est le danger?
Sequelize utilise des opérateurs de caractères par défaut. L'utilisation de Sequelize sans alias symboliques améliore bien sûr la sécurité. Bien que l'absence d'alias de chaîne rende l'injection d'opérateurs extrêmement improbable, nous devons toujours valider et nettoyer correctement les entrées utilisateur.
Et l'option operatorAliases elle-même vous permet de définir si les opérateurs d'alias seront disponibles. Voici à quoi ressemble un exemple d'activation dans le code:
Quand tout fonctionne bien
Regardons le code de l'application de démonstration. Le fichier de modèle user.model.js contient: Vous
pouvez voir qu'il y a trois champs dans la table des utilisateurs et qu'ils ont tous un type de données chaîne.
Le fichier de contrôleur auth.controller.js contient:
Le code utilise la méthode findOne sur le modèle User. Et la méthode findOne retourne la première ligne de la base de données en fonction de la condition de requête passée. Dans ce cas, l'application reçoit les données de nom d'utilisateur et de mot de passe de l'utilisateur, les applique à une requête sur la table des utilisateurs.
La requête générée dans ce cas ressemblera à quelque chose comme ceci:
SELECT `id`, `username`, `email`, `password`, `createdAt`, `updatedAt` FROM `users` AS `users` WHERE `users`.`username` = :username AND `users`.`password` = :password LIMIT 1;
Étant donné que ORM est utilisé pour former des requêtes, l'injection SQL triviale ne fonctionnera pas. Si aucune correspondance d'utilisateur n'est trouvée dans la base de données, l'application renverra l'erreur Utilisateur introuvable. Si les données d'entrée correspondent au niveau de la base de données, l'application comparera le mot de passe entré avec le mot de passe stocké dans la base de données, et renverra un "Mot de passe invalide!" s'il ne correspond pas, ou un jeton d'autorisation en cas de succès. L'algorithme de validation des données d'entrée a été choisi spécifiquement pour tester la vulnérabilité.
Le tableau contiendra les données suivantes: L'
autorisation fonctionne correctement.
Qu'en est-il des opérateurs et des alias?
Les alias sont indiqués par le symbole «$», la syntaxe des alias est similaire à MongoDB. Des opérateurs de recherche, des comparaisons et bien d'autres sont à notre disposition. Malgré le typage fort des données dans le modèle, le transfert des données de l'utilisateur vers l'ORM au format JSON implique une normalisation. Et ici, le plaisir commence!
Quand le problème frappe le DOM
Attaque par lots
Ce type de requête à l'application lance une requête à la base de données:
Exécution (par défaut): Avec cette attaque, vous pouvez vérifier la validité de plusieurs connexions pour un mot de passe spécifique dans une requête au serveur et vice versa. L'attaque fonctionne dans la dernière version de la bibliothèque pour décembre 2020 (6.3.5) et avec l'option operatorsAliases désactivée.
SELECT `id`, `username`, `email`, `password`, `createdAt`, `updatedAt` FROM `users` AS `users` WHERE `users`.`username` IN ('admin', 'more', 'much more') AND `users`.`password` = 'wrong pass' LIMIT 1;
Attaque de conversion de type de données
Si vous transmettez des données comme ...
... à l'application , rien ne se passera dans notre cas. Bien que la condition logique dans la base de données soit correcte, la vérification du mot de passe dans l'application étudiée au niveau de l'application et la comparaison de différents types de données ne peuvent pas retourner true.
Attaque d'opérateur de comparaison
Selon les données de la capture d'écran, une requête sera générée dans la base de données de la forme: La base de données renvoie des données, car il y a une correspondance entre username = admin et un mot de passe qui n'est pas égal à «aaa». Afin de suivre complètement le processus d'autorisation, nous devons obtenir un mot de passe.
SELECT `id`, `username`, `email`, `password`, `createdAt`, `updatedAt` FROM `users` AS `users` WHERE `users`.`username` = 'admin' AND `users`.`password` != 'aaa' LIMIT 1;
Attaque par recherche de regex et de chaîne
Vous pouvez obtenir les données brutes en utilisant les alias pour les opérateurs de recherche $ like ou les opérateurs $ regexp pour travailler avec des expressions régulières.
Lorsque le symbole ne converge pas, une erreur sera générée indiquant que l'utilisateur n'a pas été trouvé.
Si le symbole correspond, il y aura une erreur concernant le mauvais mot de passe. Une requête du formulaire est exécutée dans la base de données: Ainsi, caractère par caractère, vous pouvez restaurer les données de la table.
SELECT `id`, `username`, `email`, `password`, `createdAt`, `updatedAt` FROM `users` AS `users` WHERE `users`.`username` = 'admin' AND `users`.`password` LIKE 'E%' LIMIT 1;
Attaque de comparaison de colonnes dans une table
Il existe un alias intéressant $ col qui vous permet de comparer un champ à un champ.
La requête à la base de données va: Exécuter la requête suivante vers la base de données: Ainsi, elle remplira la condition logique au niveau de la base de données.
SELECT `id`, `username`, `email`, `password`, `createdAt`, `updatedAt` FROM `users` AS `users` WHERE `users`.`username` = 'admin' AND `users`.`password` = `aaaaa` LIMIT 1;
SELECT `id`, `username`, `email`, `password`, `createdAt`, `updatedAt` FROM `users` AS `users` WHERE `users`.`username` = 'admin' AND `users`.`password` = `password` LIMIT 1;
Se débarrasser des vulnérabilités
- Vous devez installer la dernière version de la bibliothèque Sequalize, où la prise en charge des alias a été supprimée.
( Source )
- Désactivez l'utilisation des alias en définissant operatorAliases: false.
- Validez soigneusement les types de données et leurs valeurs auprès de l'utilisateur avant de les utiliser dans l'ORM.
Merci pour ton intérêt!