5

のphpドキュメントページにescapeshellcmd警告があります:

コマンド文字列全体で escapeshellcmd() を使用する必要がありますが、それでも攻撃者は任意の数の引数を渡すことができます。単一の引数をエスケープするには、代わりに escapeshellarg() を使用する必要があります。

これから何を理解するのですか:

  1. escpaeshellarg で既にエスケープされている引数を含め、escapeshellcmd を使用して常にコマンド文字列全体をエスケープする必要がありますか?
  2. パラメータではないコマンド項目のみをエスケープする必要がありますか (あなたが私に尋ねた場合に行うべき唯一の論理的なこと)?
  3. これら 2 つの関数が互いに補完し合う方法についてさらに混乱を招くこの疑わしい警告を無視する必要がありますか?

ありがとう、コスミン

4

3 に答える 3

7

要するに

  • escapeshellarg:引数を一重引用符で囲むために使用され、引数内の引用符をエスケープします。
  • escapeshellcmd:シェルのメタ文字、つまり <,>,| をエスケープするために使用されます。等

お使いのバージョンの php がコマンドの実行を bash に依存していると仮定すると、bash のマニュアルからわかるように、

文字を一重引用符で囲むと、引用符内の各文字のリテラル値が保持されます。バックスラッシュが前にある場合でも、単一引用符の間に単一引用符が出現しない場合があります。

したがって、コマンドを作成する次の方法で十分であるという結論に達することができます。

$c = escapeshellcmd( $cmd ) . ' ' . escapeshellarg( $arg1 );

ただし、$c を exec、system、passthru などの関数のいずれかに渡す必要がある場合は、問題が発生する可能性があります。経験的な分析によると、これらの関数は一部の文字を評価できることが示されています。例として、これを試してください:

$cmd = 'echo';
$arg = 'TEST\0ING'; // Since we are using single quotes, \0 shouldn't be evaluated as a null byte char
$c = escapeshellcmd( $cmd ) . ' ' . escapeshellarg( $arg1 ); // echo 'TEST\0ING'
exec( $c . ' > output.txt'); // writes TEST without the ING to output.txt

exec 関数は '\0' をヌル バイト文字として評価するため、output.txt には '\0' までのデータのみが含まれます。これは、PHP 5.4.6 を実行する Ubuntu でテストされています。私の意見では、データの文字通りの意味が失われているため、これはバグです。そのため、シェルのメタ文字であるバックスラッシュ '\' もエスケープするため、完全な文字列に対して escapeshellcmd を使用する方が比較的安全です。

$c = escapeshellcmd( $cmd . ' ' . escapeshellarg( $arg1 ) );
exec( $c . ' > output.txt'); // writes TEST\0ING to output.txt

このアプローチの欠点は、他のメタ文字もエスケープされ、引数が渡されるプログラム ($cmd) によってエスケープ解除する必要があることです。

完全なコマンド文字列で escapeshellcmd を使用しなかったことに注意してください。「>」がエスケープされないように、「> output.txt」の部分を省略しました。

結論:

  • コマンドライン引数として文字列を渡さないようにしてください。代わりに、データをファイルに書き込み、ファイルから読み取ります。このようにして、渡されるデータが変更されていないことを確認できます。

  • 文字列をコマンドライン引数として渡す必要がある場合は、常に英数字であることを確認してください。

  • 文字列をコマンド ライン引数として渡す必要がある場合は、完全な文字列に対して escapeshellcmd を使用する方が比較的安全です。

于 2013-03-28T02:57:00.197 に答える
2

escapeshellcmdしたがって、複数のコマンドが実行されるのを防ぐと思います。

escapeshellcmd() は、シェル コマンドをだまして任意のコマンドを実行させるために使用される可能性のある文字列内のすべての文字をエスケープします。

escapeshellargユーザーが提供した引数が1つの引数であることを確認することです。

escapeshellarg() は、文字列を一重引用符で囲み、既存の一重引用符を引用/エスケープして、文字列をシェル関数に直接渡し、単一の安全な引数として扱うことができるようにします。

したがって、基本的には、escapeshellarg(あなたのプログラムが) コマンドを定義している場合にのみ、ユーザーが提供する引数ごとに使用する必要がありますが、ユーザーがコマンドを指示する場合 (本当にしっかりしたサーバー権限が設定されていない限り、これはすでにかなり不安定です) と引数。

免責事項: これはドキュメントの私の解釈です。

編集:

ここでドキュメントが非常に混乱していることに同意します。この警告は、これをコマンド全体にラップしても、ユーザーがこのような引数を使用することを妨げないことを意味していると思います

actualArg -someEvilFlag

また

actualArg -someEvilFlag evilFlagArgument
于 2013-03-22T19:16:07.997 に答える
1

私はescapeshellargとescapeshellcmdの違いは何ですか?これは、それぞれのメリットについてさらに詳しく説明します。

フォローアップすると思いますが、このユーザー入力を受け入れて、escapshellcmdのみを使用してシェルにスローすると、とにかくうまく終了しない可能性があります。私はサニタイズと入力検証に焦点を当て、上記の関数をこのコードのセキュリティプロセスの「最終部分」として使用します。

于 2013-03-22T19:02:01.917 に答える