10

現在、多数の外部ツールを実行するアプリケーションを構築しています。多くの場合、ユーザーがシステムに入力した情報をこれらのツールに渡す必要があります。

明らかに、これはセキュリティ上の大きな悪夢が待っています。

残念ながら、IDbCommand オブジェクトがデータベースに対して行うのと同じ種類のインジェクション攻撃に対する保護を提供しながら、コマンド ライン プログラムを実行する .NET Framework のクラスはまだ見つかっていません。

現在、非常に原始的な文字列置換を使用していますが、これはかなり不十分であると思われます。

protected virtual string Escape(string value)
{
      return value
        .Replace(@"\", @"\\")
        .Replace(@"$", @"\$")
        .Replace(@"""", @"\""")
        .Replace("`", "'")
      ;
}

コマンドライン インジェクション攻撃を防ぐために皆さんは何をしていますか? 非常に厳密で、文字のごく一部のサブセットのみを許可する正規表現を実装する予定ですが、もっと良い方法があるかどうか疑問に思っていました。

いくつかの説明:

  • これらのツールの一部には、プログラミングできる API がありません。もしそうなら、私たちはこの問題を抱えていないでしょう.
  • ユーザーは実行するツールを選択するのではなく、選択したツールが使用するメタデータを入力します (たとえば、著作権表示などのメタデータをターゲット ファイルに挿入します)。
4

7 に答える 7

5

プログラムを直接実行していますか、それともシェルを経由していますか? 実行可能ファイルにフル パス名を指定し、シェルを式から除外して、常に外部プログラムを起動する場合、コマンド ライン インジェクションの影響を実際に受けることはありません。

編集: DrFloyd、シェルはバックティックなどの評価を担当します。シェルなし、シェル評価なし。明らかに、あなたが呼び出しているプログラムの潜在的なセキュリティ上の落とし穴を認識する必要がありますが、この質問はそれに関するものではないと思います。

于 2008-09-04T21:18:10.723 に答える
2

WindowsのC++では、必要に応じて\と "をエスケープし、引数を引用符で囲んでShellExecuteします。次に、引用符内のすべてをテキストとして扱う必要があります。

これは次のことを示しているはずです。


#include <iostream>
#include <string>
#include <windows.h>
#include <cstdlib>
using namespace std;

// Escape and quote string for use as Windows command line argument
string qEscape(const string& s) {
    string result("\"");
    for (string::const_iterator i = s.begin(); i != s.end(); ++i) {
        const char c = *i;
        const string::const_iterator next = i + 1;
        if (c == '"' || (c == '\\' && (next == s.end() || *next == '"'))) {
            result += '\\';
        }
        result += c;
    }
    result += '"';
    return result;
}

int main() {
    // Argument value to pass: c:\program files\test\test.exe
    const string safe_program = qEscape("c:\\program files\\test\\test.exe");
    cout << safe_program << " ";

    // Argument value to pass: You're the "best" around.
    const string safe_arg0 = qEscape("You're the \"best\" around.");

    // Argument value to pass: "Nothing's" gonna ever keep you down.
    const string safe_arg1 = qEscape("\"Nothing's\" gonna ever keep you down.");

    const string safe_args = safe_arg0 + " " + safe_arg1;
    cout << safe_args << "\n\n";

    // c:\program files\test\  to pass.
    const string bs_at_end_example = qEscape("c:\\program files\\test\\");
    cout << bs_at_end_example << "\n\n";

    const int result = reinterpret_cast<int>(ShellExecute(NULL, "open", safe_program.c_str(), safe_args.c_str(), NULL, SW_SHOWNORMAL));
    if (result < 33) {
        cout << "ShellExecute failed with Error code " << result << "\n";
        return EXIT_FAILURE;
    }
}

しかし、どの方法を使用する場合でも、それが実際に注入を防ぐことを確認するために、それから地獄をテストする必要があります。

于 2008-09-07T22:05:48.583 に答える
2

新しいプロセスをProcess.Startするときは、コマンド ライン全体を自分で作成するのではなく、Parameters 引数にパラメーターを指定します。

適切なテストを行う時間はありませんが、ある程度は保護するのに役立つと思います。

これは明日テストします。

編集:ああ、また誰かに殴られた。しかし、ここに別のポイントがあります: Console.InputStream (正確な名前を思い出せません) を使用して、パラメーターを渡す代わりにデータを提供してみてください。それは可能な解決策ですか? CONデバイスから読み取るようにコマンドを修正し、代わりに入力ストリームを介してデータを提供します。

于 2008-09-04T21:30:07.107 に答える
2

インジェクションを防ぐためにブラックリストを使用しないでください。コードを挿入する方法がn通りある場合、 n - m where m > 0を考えるでしょう。

受け入れられたパラメーター (またはパターン) のホワイトリストを使用します。本質的にはるかに制限的ですが、それがセキュリティの性質です。

于 2008-10-23T13:51:08.220 に答える
0

コマンド ラインを使用せずにプログラムでツールを起動できる場合は、おそらくそれが最適なオプションです。そうしないと、何もするためのアクセス権がまったくないユーザーを介してコマンドラインツールを実行する可能性があります(おそらく、害を及ぼすことのできない単一のディレクトリを除く)...ただし、ツールによっては、ツールが壊れる可能性がありますツールが何をするかについて。

ツールがユーザーからの入力を必要とする外部に面したアプリケーションからコマンドラインツールを実際に呼び出す必要がなかったため、この問題に直面する必要はありませんでした。

于 2008-09-04T21:19:52.963 に答える
0

うーん...

ユーザーが実行できる有効なコマンドのリストがあるようです。しかし、それらすべてを実行する必要はありません。

実際のコマンド ラインを実行して、少なくとも「安全な」場所にファイルが存在することを確認してください。

より多くのインターフェースで問題を解決し、使用できるコマンドとパラメーターのドロップダウンを提供することもできます。それはあなたにとってより多くの作業ですが、最終的にはユーザーの役に立ちます。

于 2008-09-04T21:21:49.683 に答える
0

プログラムを直接実行していますか、それともシェルを経由していますか? 実行可能ファイルに完全なパス名を指定し、シェルを方程式から除外して、常に外部プログラムを起動する場合、コマンド ライン インジェクションの影響を実際に受けることはありません。

@Curt Hagenlocherバックティックはあなたを殺すことができます。Windows システムの設定が「間違っている」場合、または UNIX システムで許可されている場合は、dir &bt;del *&bt; 最初に del * コマンドを実行し、次に del * の代わりに出力を使用します。この場合、dir (または ls) には何もないため問題になりません。

于 2008-09-04T21:27:33.790 に答える