将用户输入安全地传递给命令

将用户输入安全地传递给命令

我有一个守护进程daemon在服务器 A 中运行。

那里有一个基于参数的脚本来控制守护进程daemon_adm.py(服务器 A)。通过这个脚本,我可以插入daemon来自用户输入的“消息” 。自由文本,无论您喜欢什么。

然后,服务器 B 中有一个daemon_adm.py使用 phpseclib 的 SSH2 类在 PHP 中使用的 Web 界面。

我知道强烈建议不要将用户输入传递到命令行,但是,必须有一种方法将文本从 Web 服务器 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
?>

这足够安全还是很复杂?

- 编辑 -

Barmar 指出的一种间接解决方案是daemon_adm.py接受来自 stdin 的文本数据,而不是作为 shell 可解析参数。

答案1

ssh2::exec()返回一个流,该流连接到远程命令的stdinstdout、 和。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

要在 shell 代码片段中插入字符串并安排 shell 按字面解释该字符串,有两种相对简单的方法:

  • 用单引号将该字符串引起来,并将每个单引号替换'为 4 个字符的字符串'\''
  • 在每个 ASCII 标点字符前添加前缀\(也可以为其他字符添加前缀),并用'␤'or替换换行符"␤"(单引号或双引号之间的换行符)。

通过 SSH 调用远程命令时,请记住远程 shell 会扩展该命令,此外,如果您通过本地 shell 调用 SSH,本地 shell 也会执行扩展,因此您需要引用两次。

PHP 提供了escapeshellarg转义 shell 特殊字符的函数。斯塞exec执行扩展,在要保护的字符串上调用两次。

请注意,这适用于文本字符串,但不适用于字节字符串。大多数 shell 不会让空字节通过。

另一种不太容易出错并允许任意字节字符串通过的方法是,但需要更改另一端运行的内容在远程命令的标准输入上传递字符串

答案3

你可以做类似的事情...

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

相关内容