En este artículo, aprenderemos cómo llamar correctamente los comandos del sistema usando Node.js para evitar vulnerabilidades comunes de inyección de línea de comandos.
El método que a menudo usamos para llamar a los comandos es el child_process.exec más simple. Tiene un patrón de uso muy simple; Pasa en un comando de cadena y pasa un resultado de procesamiento de error o comando a la función de devolución de llamada.
Aquí hay un ejemplo muy típico de los comandos de su sistema de llamadas a través de child_process.exec.
La copia del código es la siguiente:
child_process.exec ('ls', function (err, data) {
console.log (datos);
});
Sin embargo, ¿qué sucede cuando necesita agregar algunos parámetros enviados por el usuario al comando que llama? La solución obvia es encadenar la entrada del usuario directamente con su comando. Sin embargo, mis años de experiencia me dicen: cuando envíe cuerdas conectadas de un sistema a otro, algún día habrá problemas.
La copia del código es la siguiente:
var ruta = "entrada del usuario";
child_process.exec ('ls -l' + ruta, función (err, data) {
console.log (datos);
});
¿Por qué la cadena de conexión tiene problemas?
Bueno, porque bajo el motor child_process.exec, se llamará a la ejecución de "/bin/sh". No el programa objetivo. El comando enviado acaba de pasar a un nuevo proceso "/bin/sh 'para ejecutar el shell. El nombre de child_process.exec es algo engañoso: este es un intérprete bash, no un programa. Esto significa que todos los caracteres de shell pueden tener consecuencias devastadoras si los parámetros ingresados por el usuario se ejecutan directamente.
La copia del código es la siguiente:
[PID 25170] Execve ("/bin/sh", ["/bin/sh", "-c", "ls -l entrada de usuario"], [/ * 16 vars */]
Por ejemplo, un atacante podría usar un punto y coma ";"; Para finalizar el comando e iniciar una nueva llamada, y podrían usar Backticks o $ () para ejecutar el subcomando. También hay muchos abusos potenciales.
Entonces, ¿cuál es la forma correcta de llamarlo?
execfile / engendro
Spawn y ExecFile toman un parámetro de matriz adicional, que no es un entorno de shell que pueda ejecutar otros comandos y no ejecutará comandos adicionales.
Usemos ExecFile y Spawn para modificar el ejemplo anterior para ver cómo las llamadas del sistema son diferentes y por qué no es susceptible a la inyección de comandos.
child_process.execfile
La copia del código es la siguiente:
var child_process = require ('child_process');
Var ruta = "."
child_process.execfile ('/bin/ls', ['-l', ruta], function (err, resultado) {
console.log (resultado)
});
Ejecución de llamadas del sistema
La copia del código es la siguiente:
[PID 25565] EXECVE ("/bin/ls", ["/bin/ls", "-l", "."], [/ * 16 vars */]
child_process.spawn
Los ejemplos de uso de reemplazo de desove son muy similares.
La copia del código es la siguiente:
var child_process = require ('child_process');
Var ruta = "."
var ls = child_process.spawn ('/bin/ls', ['-l', ruta])
ls.stdout.on ('data', function (data) {
console.log (data.toString ());
});
Ejecución de llamadas del sistema
La copia del código es la siguiente:
[PID 26883] Execve ("/bin/ls", ["/bin/ls", "-l", "."], [/ * 16 vars */
Al usar Spawn o ExecFile, nuestro objetivo es ejecutar solo un comando (parámetro). Esto significa que el usuario no puede ejecutar el comando inyectado porque /bin /ls no sabe cómo manejar backticks o pipe o;. Lo que explicará su /bin /bash son los parámetros de esos comandos. Es similar a usar un parámetro para pasar los parámetros en una consulta SQL, si está familiarizado con él.
Pero también hay una advertencia: usar Spawn o ExecFile no siempre es seguro. Por ejemplo, ejecutar /bin /encontrar y pasar los parámetros de entrada del usuario aún puede hacer que el sistema quede atrapado. El comando Find tiene algunas opciones que permiten leer/escribir de archivos arbitrarios.
Entonces, aquí hay alguna orientación sobre Node.js Ejecutando comandos del sistema:
Evite usar child_process.exec, especialmente cuando necesita incluir parámetros ingresados por el usuario, recuerde.
Intente evitar dejar que los usuarios pasen los parámetros. Usar selecciones es mucho mejor que hacer que los usuarios ingresen cadenas directamente.
Si tiene que permitir que el usuario ingrese parámetros, consulte los parámetros del comando ampliamente, determine qué opciones son seguras y cree una lista blanca.