
daemon
サーバー A でデーモンを実行しています。
そこには、デーモンdaemon_adm.py
(サーバー A) を制御するための引数ベースのスクリプトがあります。このスクリプトを通じて、ユーザー入力からの「メッセージ」を挿入できますdaemon
。自由なテキストで、好きなようにできます。
daemon_adm.py
次に、サーバー B には、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
?>
これは十分安全ですか、それとも複雑ですか?
- 編集 -
daemon_adm.py
Barmar が示した間接的な解決策の 1 つは、シェルの解析可能な引数としてではなく、stdin からのテキスト データを受け入れるようにすることです。
答え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
シェル スニペットに文字列を挿入し、シェルがその文字列を文字通りに解釈するように設定するには、比較的単純な 2 つの方法があります。
- 文字列を一重引用符で囲み、各一重引用符を
'
4 文字の文字列に置き換えます'\''
。 - 各 ASCII 句読点文字の前に を付けます
\
(他の文字の前に付けることもできます)。また、改行文字を または''
(""
一重引用符または二重引用符の間の改行) に置き換えます。
SSH 経由でリモート コマンドを呼び出す場合は、リモート シェルがコマンドを展開すること、さらに、ローカル シェル経由で SSH を呼び出す場合はローカル シェルも展開を実行するため、引用符を 2 回使用する必要があることに注意してください。
PHPはescapeshellarg
シェルの特殊文字をエスケープする関数。exec
展開を実行するには、保護する文字列に対して 2 回呼び出します。
これはテキスト文字列には適していますが、バイト文字列には適していないことに注意してください。ほとんどのシェルは null バイトを通過させません。
エラーが発生しにくく、任意のバイト文字列を通過させるが、反対側で実行されるものを変更する必要がある別のアプローチは、リモートコマンドの標準入力に文字列を渡す。
答え3
次のようなこともできます...
$ssh->enablePTY();
$ssh->exec('/path/to/daemon_adm.py');
$ssh->write('...');
echo $ssh->read();