Dans cet article, nous apprendrons à appeler correctement les commandes du système à l'aide de Node.js pour éviter les vulnérabilités d'injection de ligne de commande communes.
La méthode que nous utilisons souvent pour appeler les commandes est la plus simple child_process.exec. Il a un modèle d'utilisation très simple; Il passe dans une commande String et transmet une erreur ou un résultat de traitement de commande à la fonction de rappel.
Voici un exemple très typique de vos commandes de système d'appel via child_process.exec.
La copie de code est la suivante:
child_process.exec ('ls', fonction (err, data) {
console.log (données);
});
Cependant, que se passe-t-il lorsque vous devez ajouter des paramètres intentés par l'utilisateur à la commande que vous appelez? La solution évidente consiste à lancer directement l'entrée de l'utilisateur avec votre commande. Cependant, mes années d'expérience me disent: lorsque vous envoyez des chaînes connectées d'un système à un autre, il y aura un jour des problèmes.
La copie de code est la suivante:
var path = "entrée utilisateur";
child_process.exec ('ls -l' + chemin, fonction (err, data) {
console.log (données);
});
Pourquoi la chaîne de connexion a-t-elle des problèmes?
Eh bien, car dans le moteur Child_process.exec, l'exécution de "/ bin / sh" sera appelée. Pas le programme cible. La commande envoyée vient de passer à un nouveau processus "/ bin / sh 'pour exécuter le shell. Le nom de child_process.exec est quelque peu trompeur - il s'agit d'un interprète bash, pas d'un programme. Cela signifie que tous les caractères de shell peuvent avoir des conséquences dévastatrices si les paramètres entrés par l'utilisateur sont directement exécutés.
La copie de code est la suivante:
[PID 25170] EXECVE ("/ bin / sh", ["/ bin / sh", "-c", "ls -l user input"], [/ * 16 vars * /]
Par exemple, un attaquant pourrait utiliser un point-virgule ";" Pour mettre fin à la commande et démarrer un nouvel appel, et ils pourraient utiliser Backticks ou $ () pour exécuter la sous-commande. Il existe également de nombreux abus potentiels.
Alors, quelle est la bonne façon de l'appeler?
Execfile / Spawn
Spawn et Execfile prennent un paramètre de tableau supplémentaire, qui n'est pas un environnement de shell qui peut exécuter d'autres commandes et ne s'exécutera pas de commandes supplémentaires.
Utilisons Execfile et Spawn pour modifier l'exemple précédent pour voir en quoi les appels système sont différents et pourquoi il n'est pas susceptible de l'injection de commande.
child_process.execfile
La copie de code est la suivante:
var child_process = require ('child_process');
var path = "."
child_process.execfile ('/ bin / ls', ['-l', path], fonction (err, result) {
console.log (résultat)
});
Appels système en cours d'exécution
La copie de code est la suivante:
[PID 25565] EXECVE ("/ bin / ls", ["/ bin / ls", "-l", "."], [/ * 16 vars * /]
child_process.spawn
Des exemples d'utilisation du remplacement de frait sont très similaires.
La copie de code est la suivante:
var child_process = require ('child_process');
var path = "."
var ls = child_process.spawn ('/ bin / ls', ['-l', path])
ls.stdout.on ('data', fonction (data) {
console.log (data.toString ());
});
Appels système en cours d'exécution
La copie de code est la suivante:
[PID 26883] EXECVE ("/ bin / ls", ["/ bin / ls", "-l", "."], [/ * 16 vars * /
Lorsque vous utilisez Spawn ou Execfile, notre objectif est d'exécuter une seule commande (paramètre). Cela signifie que l'utilisateur ne peut pas exécuter la commande injectée car / bin / ls ne sait pas comment gérer les backticks ou le tuyau ou;. Ce que son / bin / bash expliquera, ce sont les paramètres de ces commandes. Il est similaire à l'utilisation d'un paramètre pour transmettre des paramètres dans une requête SQL, si vous le savez.
Mais il y a aussi un avertissement: utiliser Spawn ou Execfile n'est pas toujours sûr. Par exemple, l'exécution / bin / finir et le passage des paramètres d'entrée utilisateur peut toujours entraîner le piégeage du système. La commande Find a certaines options qui permettent la lecture / l'écriture de fichiers arbitraires.
Donc, voici quelques conseils sur les commandes du système d'exécution de Node.js:
Évitez d'utiliser child_process.exec, surtout lorsque vous devez inclure des paramètres saisis par l'utilisateur, n'oubliez pas.
Essayez d'éviter de laisser passer les utilisateurs. L'utilisation de sélections est bien meilleure que de faire entrer directement les utilisateurs.
Si vous devez permettre à l'utilisateur de saisir les paramètres, reportez-vous aux paramètres de la commande, déterminez quelles options sont sûres et créez une liste blanche.