將使用者輸入安全地傳遞給命令

將使用者輸入安全地傳遞給命令

我有一個守護程序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();

相關內容