Passando com segurança a entrada do usuário para o comando

Passando com segurança a entrada do usuário para o comando

Eu tenho um daemon daemonem execução no Servidor A.

Lá, há um script baseado em argumentos para controlar o daemon daemon_adm.py(Servidor A). Através deste script posso inserir "mensagens" daemonvindas da entrada do usuário. Texto livre, como você quiser.

Depois, há uma interface web no Servidor B para daemon_adm.pyPHP usando a classe SSH2 do phpseclib.

Eu sei que é fortemente desencorajado passar a entrada do usuário para a linha de comando, mas bem, deve haver uma maneira de passar o texto do servidor web B para daemon_adm.pyo servidor A.

Como posso passar com segurança um texto como argumento para um utilitário de linha de comando?

Mesmo se eu repetir os argumentos e canalizá-los daemon_adm.pyassim:

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

como este comando é executado por uma interface ssh com uma string formatada, o código pode ser injetado

<?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"
?>

Minha opção atual em mente é codificar cada entrada do usuário para base64 (que, até onde eu sei, não usa aspas e espaços em seu conjunto de caracteres) e decodificá-la daemon_adm.pyassim:

<?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
?>

Isso é seguro o suficiente ou complicado?

--EDITAR--

Uma solução indireta, conforme indicado por Barmar, seria daemon_adm.pyaceitar os dados de texto do stdin, e não como um argumento analisável pelo shell.

Responder1

ssh2::exec()retorna um fluxo, que está conectado a stdin, stdoute stderrdo comando remoto. Então você pode fazer:

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

Se não quiser passar os parâmetros via stdin, você pode usarescapeshellarg():

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

Responder2

Para inserir uma string em um snippet de shell e fazer com que o shell interprete a string literalmente, existem duas abordagens relativamente simples:

  • Coloque a string entre aspas simples e substitua cada aspa simples 'pela string de 4 caracteres '\''.
  • Prefixe cada caractere de pontuação ASCII com \(você também pode prefixar outros caracteres) e substitua as novas linhas por '␤'ou "␤"(nova linha entre aspas simples ou duplas).

Ao invocar um comando remoto por SSH, lembre-se de que o shell remoto expandirá o comando e, além disso, se você estiver invocando o SSH por meio de um shell local, o shell local também realizará a expansão, portanto, você precisará citar duas vezes.

PHP fornece oescapeshellargfunção para escapar de caracteres especiais do shell. Desde entãoexecexecuta a expansão, chame-o duas vezes na string que deseja proteger.

Observe que isso é adequado para cadeias de texto, mas não para cadeias de bytes. A maioria dos shells não permite a passagem de bytes nulos.

Outra abordagem que é menos propensa a erros e permite a passagem de cadeias de bytes arbitrárias, mas requer a alteração do que é executado na outra extremidade, épasse a string na entrada padrão do comando remoto.

Responder3

Você poderia fazer algo como...

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

informação relacionada