Безопасная передача пользовательского ввода в команду

Безопасная передача пользовательского ввода в команду

У меня есть демон, daemonработающий на сервере A.

Там есть скрипт на основе аргументов для управления демоном daemon_adm.py(Сервер А). С помощью этого скрипта я могу вставлять "сообщения" в daemonисходящий от пользователя ввод. Свободный текст, какой вам нравится.

Затем на сервере B имеется веб-интерфейс для daemon_adm.pyPHP, использующий класс SSH2 из phpseclib.

Я знаю, что передавать пользовательский ввод в командную строку настоятельно не рекомендуется, но должен же быть способ передать текст с веб-сервера B на daemon_adm.pyсервер A.

Как безопасно передать текст в качестве аргумента утилите командной строки?

Даже если я повторю аргументы и перескажу их daemon_adm.pyвот так:

<?php 
$command = '/path/to/daemon_adm.py "'.$text.'"';
ssh->exec($command);
// or whatever other library or programming language
?>

поскольку эта команда выполняется интерфейсом ssh с форматированной строкой, код может быть внедрен

<?php 
$text = 'safetext"; echo "hazard"';
$command = '/path/to/daemon_adm.py "'.$text.'"';
ssh->exec($command);
// command sent: /path/to/daemon_adm.py "safetext"; echo "hazard"
?>

На данный момент я рассматриваю вариант кодирования всех вводимых пользователем данных в base64 (который, насколько мне известно, не использует кавычки и пробелы в своем наборе символов) и декодирования их следующим daemon_adm.pyобразом:

<?php 
$text = 'safetext"; echo "hazard"';

// Enconding it to base64

$command = '/path/to/daemon_adm.py '.$encoded_text;
ssh->exec($command);

// command sent: /path/to/daemon_adm.py c2FmZXRleHQiOyBlY2hvICJoYXphcmQi
?>

Достаточно ли это безопасно или запутанно?

-- РЕДАКТИРОВАТЬ --

Одним из косвенных решений, на которое указал Бармар, было бы daemon_adm.pyпринятие текстовых данных из stdin, а не как аргумента, анализируемого оболочкой.

решение1

ssh2::exec()возвращает поток, который подключен к stdin, stdout, и stderrудаленной команды. Таким образом, вы можете сделать:

$command = '/path/to/daemon_adm.py';
$stream = $ssh->exec($command);
fwrite($stream, "$text\n");

Если вы не хотите передавать параметры через stdin, вы можете использоватьescapeshellarg():

$command = '/path/to/daemon_adm.py ' . escapeshellarg($text);
$ssh->exec($command);

решение2

Чтобы вставить строку во фрагмент оболочки и сделать так, чтобы оболочка интерпретировала строку буквально, есть два относительно простых подхода:

  • Заключите строку в одинарные кавычки и замените каждую одинарную кавычку 'строкой из 4 символов '\''.
  • Добавляйте к каждому символу пунктуации ASCII префикс \(вы можете добавлять и другие символы), а также заменяйте символы новой строки на '␤'или "␤"(переход на новую строку между одинарными или двойными кавычками).

При вызове удаленной команды через SSH помните, что удаленная оболочка расширит команду, и, кроме того, если вы вызываете SSH через локальную оболочку, локальная оболочка также выполнит расширение, поэтому вам нужно будет заключить команду в кавычки дважды.

PHP предоставляетescapeshellargфункция экранирования специальных символов оболочки. Snceexecвыполняет расширение, вызовите его дважды для строки, которую вы хотите защитить.

Обратите внимание, что это нормально для текстовых строк, но не для байтовых строк. Большинство оболочек не пропускают нулевые байты.

Другой подход, который менее подвержен ошибкам и позволяет передавать произвольные строки байтов, но требует изменения того, что выполняется на другом конце, заключается в следующем:передать строку на стандартный ввод удаленной команды.

решение3

Вы могли бы сделать что-то вроде...

$ssh->enablePTY();
$ssh->exec('/path/to/daemon_adm.py');
$ssh->write('...');
echo $ssh->read();

Связанный контент