
我有一個守護程序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()
傳回一個流,該流連接到遠端命令的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
要在 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();