2

Pythonスクリプト、より具体的には一連の変数割り当てステートメントを出力する必要があるPHPアプリケーションがあります。

subject_prefix = 'This String From User Input'
msg_footer = """This one too."""

ユーザー入力を取得するには、subject_prefix などの内容を記述する必要があります。そのため、文字列の内容をエスケープする必要があります。次のようなものを書いてもうまくいきません。誰かが引用符や改行、または私が認識していない危険な可能性があるものを使用するとすぐに、私たちは詰め込まれます:

echo "subject_prefix = '".$subject_prefix."'\n";

そう。何か案は?

(時間の制約により、Python でアプリを書き直すことはできません。:P )

編集、数年後:

これは、Web アプリ (PHP で作成) と Mailman (Python で作成) を統合するためのものでした。後者のインストールを変更することはできなかったので、設定を管理するためにその言語で話す方法を考え出す必要がありました。

これも本当にまずい考えでした。

4

5 に答える 5

2

この関数を PHP で記述しようとしないでください。必然的に間違いを犯し、アプリケーションは必然的に任意のリモート実行エクスプロイトを持ちます。

まず、実際にどのような問題を解決しているのかを考えてみましょう。PHPからPythonにデータを取得しようとしているだけだと思います。.py ファイルではなく .ini ファイルを書き込もうとするかもしれません。Python には、優れた ini 構文パーサーConfigParserがあります。PHP で、明らかに間違っている可能性のある引用関数を作成することができます。

XML ファイルを作成することもできます。PHP と Python 用の XML パーサーとエミッターは多すぎて、ここにリストすることさえできません。

これがひどい、ひどい考えだと本当に納得できない場合は、少なくともPythonがそのようなことを行うために持っている既存の関数を使用できます。repr()

これを行うために Python スクリプトを実行する便利な PHP 関数を次に示します。

<?php

function py_escape($input) {
    $descriptorspec = array(
        0 => array("pipe", "r"),
        1 => array("pipe", "w")
        );
    $process = proc_open(
        "python -c 'import sys; sys.stdout.write(repr(sys.stdin.read()))'",
        $descriptorspec, $pipes);
    fwrite($pipes[0], $input);
    fclose($pipes[0]);
    $chunk_size = 8192;
    $escaped = fread($pipes[1], $chunk_size);
    if (strlen($escaped) == $chunk_size) {
        // This is important for security.
        die("That string's too big.\n");
    }
    proc_close($process);
    return $escaped;
}

// Example usage:
$x = "string \rfull \nof\t crappy stuff";
print py_escape($x);

このチェックは、入力がそれぞれとchunk_sizeのように見える 2 つの非常に長い文字列になるという攻撃を防ぐことを目的としています。さて、Python は一重引用符で囲まれた文字列を行の途中で終了させないため、その素朴な攻撃は正確には機能しません。継続 ("\") を適切な場所に挿入し、次のようなものを使用すると、実行されるコードを挿入できます。("hello " + ("." * chunk_size))'; os.system("do bad stuff")system()os.system(map(chr, ...))

Python ソース ファイルの行の長さにも制限があるため、読み取りと蓄積を続けるのではなく、単純に 1 つのチャンクを読み取り、さらに出力があればあきらめることを選択しました。私が知っている限りでは、それは別の攻撃ベクトルである可能性があります. Python は、システム上で任意のソース コードを作成する任意の人物に対して安全であることを意図していないため、この領域が監査される可能性は低いです。

この些細な例のためにこれをすべて考えなければならなかったという事実は、データ交換フォーマットとして Python ソース コードを使用してはならない理由のもう 1 つの例にすぎません。

于 2008-10-14T07:58:38.000 に答える
0

Python で使用していた文字列型を標準化して、トリプル クォート文字列 (""") を使用することから始めます。これにより、入力内の引用符が外れてしまうことによる問題の発生を減らすことができます。もちろん、懸念される問題の数を減らす必要があります。

文字列をエスケープするために私がしたことは、私が何を心配しているのか、そしてそれらが再び出力されているという文脈に多少依存します。引用符が問題を引き起こしていることだけが心配な場合は、""" の発生をチェックしてエスケープするだけで済みます。 )、次に、strip_tags() や他の同様の関数などのオプションを調べます。

于 2008-10-13T05:34:47.090 に答える
0

python escapingを使用する「ntriples」形式で文字列をエスケープするには、これをコーディングする必要がありました。

次の関数は、utf-8 文字列を受け取り、python (または ntriples 形式) 用にエスケープして返します。不正な utf-8 データが与えられた場合、奇妙なことをするかもしれません。xFFFF を超える Unicode 文字については理解できません。(現在) 文字列を二重引用符で囲みません。

uniord 関数は php.net のコメントから来ています。

function python_string_escape( $string ) {
    $string = preg_replace( "/\\\\/", "\\\\", $string ); # \\ (first to avoid string re-escaping)
    $string = preg_replace( "/\n/", "\\n", $string ); # \n
    $string = preg_replace( "/\r/", "\\r", $string ); # \r 
    $string = preg_replace( "/\t/", "\\t", $string ); # \t 
    $string = preg_replace( "/\"/", "\\\"", $string ); # \"
    $string = preg_replace( "/([\x{00}-\x{1F}]|[\x{7F}-\x{FFFF}])/ue",
                            "sprintf(\"\\u%04X\",uniord(\"$1\"))",
                            $string );
    return $string;
}

function uniord($c) {
    $h = ord($c{0});
    if ($h <= 0x7F) {
        return $h;
    } else if ($h < 0xC2) {
        return false;
    } else if ($h <= 0xDF) {
        return ($h & 0x1F) << 6 | (ord($c{1}) & 0x3F);
    } else if ($h <= 0xEF) {
        return ($h & 0x0F) << 12 | (ord($c{1}) & 0x3F) << 6 | (ord($c{2}) & 0x3F);
    } else if ($h <= 0xF4) {
        return ($h & 0x0F) << 18 | (ord($c{1}) & 0x3F) << 12 | (ord($c{2}) & 0x3F) << 6 | (ord($c{3}) & 0x3F);
    } else {
        return false;
    }
}
于 2009-11-28T18:47:35.033 に答える
0

もう 1 つのオプションは、データを配列またはオブジェクトとして JSON 文字列としてエクスポートし、Python コードを少し変更して新しい入力を処理することです。JSON によるエスケープは 100% 防弾ではありませんが、独自のエスケープ ルーチンよりも優れています。

また、JSON 文字列の形式が正しくない場合は、エラーを処理できます。

Python が JSON をエンコードおよびデコードするためのパッケージがあります: python-json 3.4

于 2008-10-13T07:57:21.467 に答える
-2

2 つの引数を取る関数を作成することをお勧めします: エスケープするテキストと、文字列が含まれる引用符の種類です。次に、たとえば、引用符の種類が一重引用符の場合、関数は文字列内の一重引用符をエスケープします。およびエスケープする必要があるその他の文字 (バックスラッシュ?)。

function escape_string($text, $type) {
    // Escape backslashes for all types of strings?
    $text = str_replace('\\', '\\\\', $text);

    switch($type) {
        case 'single':
            $text = str_replace("'", "\\'", $text);
            break;
        case 'double':
            $text = str_replace('"', '\\"', $text);
            break;
        // etc...
    }

    return $text;
}

一重引用符で囲まれた文字列では一重引用符をエスケープし、二重引用符で囲まれた文字列では二重引用符をエスケープしたいと思います...

于 2008-10-13T05:30:00.610 に答える