Tengo un demonio daemon
ejecutándose en el servidor A.
Allí, hay un script basado en argumentos para controlar el demonio daemon_adm.py
(Servidor A). A través de este script puedo insertar "mensajes" daemon
provenientes de la entrada del usuario. Texto libre, lo que quieras que sea.
Luego, hay una interfaz web en el Servidor B para daemon_adm.py
PHP que utiliza la clase SSH2 de phpseclib.
Sé que se desaconseja pasar la entrada del usuario a la línea de comando, pero bueno, debe haber una manera de pasar el texto desde el servidor web B al daemon_adm.py
servidor A.
¿Cómo puedo pasar de forma segura un texto como argumento a una utilidad de línea de comando?
Incluso si me hago eco de los argumentos y los canalizo de daemon_adm.py
esta manera:
<?php
$command = '/path/to/daemon_adm.py "'.$text.'"';
ssh->exec($command);
// or whatever other library or programming language
?>
dado que este comando se ejecuta mediante una interfaz ssh con una cadena formateada, se podría inyectar código
<?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"
?>
Mi opción actual en mente es codificar cada entrada del usuario en base64 (que hasta donde yo sé no usa comillas ni espacios en su conjunto de caracteres) y decodificarla de daemon_adm.py
esta manera:
<?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
?>
¿Es esto lo suficientemente seguro o complicado?
-- EDITAR --
Una solución indirecta, según lo indicado por Barmar, sería hacer que daemon_adm.py
se aceptaran los datos de texto de la entrada estándar, y no como un argumento analizable del shell.
Respuesta1
ssh2::exec()
devuelve una secuencia, que está conectada a stdin
, stdout
y stderr
del comando remoto. Entonces puedes hacer:
$command = '/path/to/daemon_adm.py';
$stream = $ssh->exec($command);
fwrite($stream, "$text\n");
Si no desea pasar los parámetros a través de stdin, puede usarescapeshellarg()
:
$command = '/path/to/daemon_adm.py ' . escapeshellarg($text);
$ssh->exec($command);
Respuesta2
Para insertar una cadena en un fragmento de shell y hacer que el shell interprete la cadena literalmente, existen dos métodos relativamente simples:
- Rodee la cadena entre comillas simples y reemplace cada comilla simple
'
por la cadena de 4 caracteres'\''
. - Anteponga cada carácter de puntuación ASCII
\
(también puede anteponer otros caracteres) y reemplace las nuevas líneas con''
o""
(nueva línea entre comillas simples o dobles).
Al invocar un comando remoto a través de SSH, tenga en cuenta que el shell remoto expandirá el comando y, además, si invoca SSH a través de un shell local, el shell local también realizará la expansión, por lo que deberá citar dos veces.
PHP proporciona laescapeshellarg
función para escapar de los caracteres especiales del shell. Desdeexec
realiza la expansión, llámalo dos veces en la cadena que deseas proteger.
Tenga en cuenta que esto está bien para cadenas de texto, pero no para cadenas de bytes. La mayoría de los shells no dejarán pasar bytes nulos.
Otro enfoque que es menos propenso a errores y permite el paso de cadenas de bytes arbitrarias, pero requiere cambiar lo que se ejecuta en el otro extremo, espasar la cadena en la entrada estándar del comando remoto.
Respuesta3
Podrías hacer algo como...
$ssh->enablePTY();
$ssh->exec('/path/to/daemon_adm.py');
$ssh->write('...');
echo $ssh->read();