如何在节点中转义shell命令的字符串?

时间:2020-12-04 16:57:27

In nodejs, the only way to execute external commands is via sys.exec(cmd). I'd like to call an external command and give it data via stdin. In nodejs there does yet not appear to be a way to open a command and then push data to it (only to exec and receive its standard+error outputs), so it appears the only way I've got to do this right now is via a single string command such as:

在node . js中,执行外部命令的惟一方法是通过sys.exec(cmd)。我想调用一个外部命令,并通过stdin提供数据。在nodejs中,似乎还没有一种方法可以打开一个命令,然后将数据推给它(只向exec发送并接收它的标准+错误输出),所以我现在要做的唯一方法似乎是通过一个字符串命令,比如:

var dangerStr = "bad stuff here";
sys.exec("echo '" + dangerStr + "' | somecommand");

Most answers to questions like this have focused on either regex which doesn't work for me in nodejs (which uses Google's V8 Javascript engine) or native features from other languages like Python.

对于这样的问题,大多数的答案都集中在regex上,它在nodejs(使用谷歌的V8 Javascript引擎)中不适合我,或者是Python等其他语言的本地特性。

I'd like to escape dangerStr so that it's safe to compose an exec string like the one above. If it helps, dangerStr will contain JSON data.

我想逃离危险,这样就可以安全地组成一个执行字符串,如上面所示。如果有帮助,dangerStr将包含JSON数据。

5 个解决方案

#1


3  

There is a way to write to an external command: process.createChildProcess (documentation) returns an object with a write method. createChildProcess isn't as convenient though, because it doesn't buffer stdout and stderr, so you will need event handlers to read the output in chunks.

有一种方法可以写入外部命令:进程。createChildProcess(文档)返回一个带有写方法的对象。createChildProcess并不是那么方便,因为它没有缓冲stdout和stderr,所以您需要事件处理程序来读取数据块。

var stdout = "", stderr = "";
var child = process.createChildProcess("someCommand");

child.addListener("output", function (data) {
    if (data !== null) {
        stdout += data;
    }
});
child.addListener("error", function (data) {
    if (data !== null) {
        stderr += data;
    }
});
child.addListener("exit", function (code) {
    if (code === 0) {
        sys.puts(stdout);
    }
    else {
        // error
    }
});

child.write("This goes to someCommand's stdin.");

#2


32  

This is what I use:

这就是我使用的:

var escapeShell = function(cmd) {
  return '"'+cmd.replace(/(["\s'$`\\])/g,'\\$1')+'"';
};

#3


13  

If you need simple solution you can use this:

如果您需要简单的解决方案,您可以使用以下方法:

function escapeShellArg (arg) {
    return `'${arg.replace(/'/g, `'\\''`)}'`;
}

So your string will be simply escaped with single quotes as Chris Johnsen mentioned.

因此,你的字符串将简单地用单引号转义,就像Chris Johnsen提到的那样。

echo 'John'\''s phone';

It works in bash because of strong quoting, feels like it also works in fish, but does not work in zsh and sh.

它在bash中工作,因为强烈的引用,感觉它也适用于鱼,但不工作在zsh和sh。

If you have bash your can run your script in sh or zsh with 'bash -c \'' + escape('all-the-rest-escaped') + '\''.

如果您有bash,您可以使用“bash -c \”+ escape(“all-the- reescape”)+“\”在sh或zsh中运行脚本。

But actually... node.js will escape all needed characters for you:

但实际上……节点。js将为您转义所有需要的字符:

var child = require('child_process')
  .spawn('echo', ['`echo 1`;"echo $SSH_TTY;\'\\0{0..5}']);

child.stdout.on('data', function (data) {
  console.log('stdout: ' + data);
});

child.stderr.on('data', function (data) {
  console.log('stderr: ' + data);
});

this block of code will execute:

此代码块将执行:

echo '`echo 1`;"echo $SSH_TTY;'\''\\0{0..5}'

and will output:

并将输出:

stdout: `echo 1`;"echo $SSH_TTY;\'\\0{0..5}

or some error.

或者一些错误。

Take a look at http://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options

看看http://nodejs.org/api/child_process.html# child_process_child_child_process_process_spaw_spawn_command_args_options

By the way simple solution to run a bunch of commands is:

顺便说一下,运行一系列命令的简单解决方案是:

require('child_process')
  .spawn('sh', ['-c', [
    'cd all/your/commands',
    'ls here',
    'echo "and even" > more'
  ].join('; ')]);

Have a nice day!

祝你有美好的一天!

#4


2  

You should never rely on escaping unknown input going to a shell parameter - there will almost always be some edge-case that you haven't thought of that allows the user to execute arbitrary code on your server.

您永远不应该依赖于将未知输入转义到shell参数—几乎总是会有一些您没有想到的边格情况,允许用户在您的服务器上执行任意代码。

Node has support for calling a command and passing each argument separately, with no escaping required. This is the safest way to do it:

Node支持调用命令并分别传递每个参数,不需要转义。这是最安全的方法:

const { spawn } = require('child_process');
// Note that the arguments are in an array, not using string interpolation
const ls = spawn('ls', ['-lh', '/usr']);

ls.stdout.on('data', (data) => {
  console.log(`stdout: ${data}`);
});

ls.stderr.on('data', (data) => {
  console.log(`stderr: ${data}`);
});

ls.on('close', (code) => {
  console.log(`child process exited with code ${code}`);
});

The documentation is here

这里的文档是

#5


-2  

If you also need to deal with special character (line-breaks etc.) you can do it this way:

如果你还需要处理特殊字符(换行符等),你可以这样做:

str = JSON.stringify(str)
    .replace(/^"|"$/g,'') //remove JSON-string double quotes
    .replace(/'/g, '\'"\'"\'') //escape single quotes the ugly bash way

This assumes you use Bash's strong-quoting via single-quotes) and the receiver can understand JSON's C-like escaping.

这假定您使用Bash的强引用通过单引号),并且接收方可以理解JSON的c类转义。

#1


3  

There is a way to write to an external command: process.createChildProcess (documentation) returns an object with a write method. createChildProcess isn't as convenient though, because it doesn't buffer stdout and stderr, so you will need event handlers to read the output in chunks.

有一种方法可以写入外部命令:进程。createChildProcess(文档)返回一个带有写方法的对象。createChildProcess并不是那么方便,因为它没有缓冲stdout和stderr,所以您需要事件处理程序来读取数据块。

var stdout = "", stderr = "";
var child = process.createChildProcess("someCommand");

child.addListener("output", function (data) {
    if (data !== null) {
        stdout += data;
    }
});
child.addListener("error", function (data) {
    if (data !== null) {
        stderr += data;
    }
});
child.addListener("exit", function (code) {
    if (code === 0) {
        sys.puts(stdout);
    }
    else {
        // error
    }
});

child.write("This goes to someCommand's stdin.");

#2


32  

This is what I use:

这就是我使用的:

var escapeShell = function(cmd) {
  return '"'+cmd.replace(/(["\s'$`\\])/g,'\\$1')+'"';
};

#3


13  

If you need simple solution you can use this:

如果您需要简单的解决方案,您可以使用以下方法:

function escapeShellArg (arg) {
    return `'${arg.replace(/'/g, `'\\''`)}'`;
}

So your string will be simply escaped with single quotes as Chris Johnsen mentioned.

因此,你的字符串将简单地用单引号转义,就像Chris Johnsen提到的那样。

echo 'John'\''s phone';

It works in bash because of strong quoting, feels like it also works in fish, but does not work in zsh and sh.

它在bash中工作,因为强烈的引用,感觉它也适用于鱼,但不工作在zsh和sh。

If you have bash your can run your script in sh or zsh with 'bash -c \'' + escape('all-the-rest-escaped') + '\''.

如果您有bash,您可以使用“bash -c \”+ escape(“all-the- reescape”)+“\”在sh或zsh中运行脚本。

But actually... node.js will escape all needed characters for you:

但实际上……节点。js将为您转义所有需要的字符:

var child = require('child_process')
  .spawn('echo', ['`echo 1`;"echo $SSH_TTY;\'\\0{0..5}']);

child.stdout.on('data', function (data) {
  console.log('stdout: ' + data);
});

child.stderr.on('data', function (data) {
  console.log('stderr: ' + data);
});

this block of code will execute:

此代码块将执行:

echo '`echo 1`;"echo $SSH_TTY;'\''\\0{0..5}'

and will output:

并将输出:

stdout: `echo 1`;"echo $SSH_TTY;\'\\0{0..5}

or some error.

或者一些错误。

Take a look at http://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options

看看http://nodejs.org/api/child_process.html# child_process_child_child_process_process_spaw_spawn_command_args_options

By the way simple solution to run a bunch of commands is:

顺便说一下,运行一系列命令的简单解决方案是:

require('child_process')
  .spawn('sh', ['-c', [
    'cd all/your/commands',
    'ls here',
    'echo "and even" > more'
  ].join('; ')]);

Have a nice day!

祝你有美好的一天!

#4


2  

You should never rely on escaping unknown input going to a shell parameter - there will almost always be some edge-case that you haven't thought of that allows the user to execute arbitrary code on your server.

您永远不应该依赖于将未知输入转义到shell参数—几乎总是会有一些您没有想到的边格情况,允许用户在您的服务器上执行任意代码。

Node has support for calling a command and passing each argument separately, with no escaping required. This is the safest way to do it:

Node支持调用命令并分别传递每个参数,不需要转义。这是最安全的方法:

const { spawn } = require('child_process');
// Note that the arguments are in an array, not using string interpolation
const ls = spawn('ls', ['-lh', '/usr']);

ls.stdout.on('data', (data) => {
  console.log(`stdout: ${data}`);
});

ls.stderr.on('data', (data) => {
  console.log(`stderr: ${data}`);
});

ls.on('close', (code) => {
  console.log(`child process exited with code ${code}`);
});

The documentation is here

这里的文档是

#5


-2  

If you also need to deal with special character (line-breaks etc.) you can do it this way:

如果你还需要处理特殊字符(换行符等),你可以这样做:

str = JSON.stringify(str)
    .replace(/^"|"$/g,'') //remove JSON-string double quotes
    .replace(/'/g, '\'"\'"\'') //escape single quotes the ugly bash way

This assumes you use Bash's strong-quoting via single-quotes) and the receiver can understand JSON's C-like escaping.

这假定您使用Bash的强引用通过单引号),并且接收方可以理解JSON的c类转义。