Как избежать строки для команды оболочки в node?
В nodejs единственный способ выполнения внешних команд - через sys.exec(cmd). Я бы хотел вызвать внешнюю команду и передать ее через stdin. В nodejs пока еще нет способа открыть команду, а затем нажимать на нее данные (только для exec и получения ее стандартных выходов + ошибок), поэтому, похоже, единственный способ, которым я должен это сделать прямо сейчас, - это с помощью одной строковой команды, такой как:
var dangerStr = "bad stuff here";
sys.exec("echo '" + dangerStr + "' | somecommand");
Большинство ответов на такие вопросы были сосредоточены на любом регулярном выражении, которое не работает для меня в nodejs (которое использует механизм Javascript Google V8) или собственных функций с других языков, таких как Python.
Мне бы хотелось избежать опасностиStr, чтобы было безопасно составить строку exec, подобную приведенной выше. Если это поможет, опасностьStr будет содержать данные JSON.
Ответы
Ответ 1
Существует способ записи во внешнюю команду: process.createChildProcess
(документация) возвращает объект с помощью метода write
. 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 stdin.");
Ответ 2
Это то, что я использую:
var escapeShell = function(cmd) {
return '"'+cmd.replace(/(["\s'$`\\])/g,'\\$1')+'"';
};
Ответ 3
Если вам нужно простое решение, вы можете использовать это:
function escapeShellArg (arg) {
return `'${arg.replace(/'/g, `'\\''`)}'`;
}
Таким образом, ваша строка будет просто экранирована одиночными кавычками, о которых говорил Крис Джонсен.
echo 'John'\' phone';
Он работает в bash
из-за сильного цитирования, похоже, что он также работает в fish
, но не работает в zsh
и sh
.
Если у вас bash
, вы можете запустить script в sh
или zsh
с помощью 'bash -c \'' + escape('all-the-rest-escaped') + '\''
.
Но на самом деле... node.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);
});
этот блок кода выполнит:
echo '`echo 1`;"echo $SSH_TTY;'\''\\0{0..5}'
и выведет:
stdout: `echo 1`;"echo $SSH_TTY;\'\\0{0..5}
или некоторая ошибка.
Взгляните на http://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options
Кстати, простое решение для запуска пула команд:
require('child_process')
.spawn('sh', ['-c', [
'cd all/your/commands',
'ls here',
'echo "and even" > more'
].join('; ')]);
Приятного дня!
Ответ 4
Вы никогда не должны полагаться на экранирование неизвестного ввода, идущего на параметр оболочки - почти всегда будет какой-то крайний случай, о котором вы не подумали, что позволяет пользователю выполнять произвольный код на вашем сервере.
Узел имеет поддержку вызова команды и передачи каждого аргумента отдельно, без необходимости экранирования. Это самый безопасный способ сделать это:
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}');
});
Документация здесь
Ответ 5
Вариант ответа Сильвена:
var escapeShell = function(string) {
// Sanitise all space (newlines etc.) to a single space
string.replace(/\s+/g, " ");
// Optionally remove leading and trailing space
string.replace(/^\s+|\s+$/g, " ");
// Quote with single quotes, escaping backslashes and single quotes
return "'" + string.replace(/(['\\])/g, '\\$1') + "'";
};
В предположении, что $
не нужно экранировать в одной кавычки (как указал Алекс), а другие типы цитат тоже не должны быть.
Ответ 6
Если вам также необходимо иметь дело со специальным символом (разрывы строк и т.д.), вы можете сделать это следующим образом:
str = JSON.stringify(str)
.replace(/^"|"$/g,'') //remove JSON-string double quotes
.replace(/'/g, '\'"\'"\'') //escape single quotes the ugly bash way
Предполагается, что вы используете Bash сильное цитирование с помощью одиночных кавычек), и получатель может понять, как экранирование JSON C-типа.