Home > Article > Web Front-end > How to safely call system commands in Node.js (to avoid injecting security vulnerabilities)
This article mainly introduces the method of safely calling system commands in Node.js (to avoid injecting security vulnerabilities). This chapter generally explains the security issues that may arise when connecting strings. Friends in need can refer to it.
In this article, we will learn how to correctly use Node.js to call system commands to avoid common command line injection vulnerabilities.
The method we often use to call commands is the simplest child_process.exec. It has a very simple usage pattern; by passing in a string command, and passing an error or command processing result back to the callback function.
Here is a very typical example of calling a system command through child_process.exec.
child_process.exec('ls', function (err, data) { console.log(data); });
However, what happens when you need to add some user-entered parameters to the command you call? The obvious solution is to string merge the user input directly with your command. However, my years of experience tell me: when you send connected strings from one system to another, something is going to go wrong one day.
var path = "user input"; child_process.exec('ls -l ' + path, function (err, data) { console.log(data); });
Why is there a problem with the connection string?
Well, because under the child_process.exec engine, "/bin/sh" will be called and executed. rather than the target program. The command that was sent is simply passed to a new '/bin/sh' process to execute the shell. The name child_process.exec is somewhat misleading - this is a bash interpreter, not starting a program. This means, All shell characters can have devastating consequences if user-entered parameters are executed directly
[pid 25170] execve("/bin/sh", ["/bin/sh", "-c", "ls -l user input"], [/* 16 vars */]
For example, an attacker can use a semicolon ";" to end a command and start a new one. Called, they can use backticks or $() to run subcommands.
So what is the correct way to call execFile/spawn 🎜>
Like spawn and execFile take an additional array parameter, which is not a parameter that can execute other commands in a shell environment, and will not run additional commands. Let us use execFile. Modify the previous example with spawn to see how the system call is different and why it is not vulnerable to command injection. The system call
child_process.spawn
is very similar to the example using spawn replacement of the system call running
. >var child_process = require('child_process'); var path = "." child_process.execFile('/bin/ls', ['-l', path], function (err, result) { console.log(result) });
When using spawn or execfile, the goal is to execute only one command (parameters). This means that the user cannot run the injected command because /bin/ls does not know how to handle backticks or pipes. or ;. What /bin/bash will do is interpret the parameters of those commands. It's similar to using
[pid 25565] execve("/bin/ls", ["/bin/ls", "-l", "."], [/* 16 vars */]if you're familiar with it but with the caveat: Using spawn or execFile is not always safe. For example, running /bin/find and passing in user input parameters can still lead to the system being compromised. The find command has some options that allow reading/writing arbitrary files. 🎜>So, here are some guidelines for running system commands in Node.js:
Avoid using child_process.exec, especially when you need to include user-entered parameters, please keep this in mind. It's much better to let the user pass in parameters, using options rather than asking the user to enter a string directly If you must allow the user to enter parameters, consult the parameters of the command extensively to determine which options are safe and establish a whitelist. List.
The above is the entire content of this chapter. For more related tutorials, please visit
Node.js video tutorialvar child_process = require('child_process'); var path = "." var ls = child_process.spawn('/bin/ls', ['-l', path]) ls.stdout.on('data', function (data) { console.log(data.toString()); });!