web-dev-qa-db-ja.com

マルチバイト文字列のstr_replace()は危険ですか?

特定のマルチバイト文字セットが与えられた場合、私は以下がそれが意図したことをしないと仮定して正しいですか?

$string = str_replace('"', '\\"', $string);

特に、入力が0xbf5cのような有効な文字を持つ可能性のある文字セットであった場合、攻撃者は0xbf22を注入して0xbf5c22を取得し、有効な文字の後に引用符のない二重引用符( ")を残すことができます。

この問題を緩和する簡単な方法はありますか、それとも最初に問題を誤解していますか?

(私の場合、文字列はHTML入力タグのvalue属性に入ります:echo 'input type = "text" value = "'。$ string。 '">';)

編集:その問題については、preg_quote()のような関数はどうですか?これには文字セット引数がないため、このシナリオではまったく役に立たないようです。文字セットをUTF-8に制限するオプションがない場合(そう、それはいいでしょう)、本当に障害者のようです。その場合、どの置換および引用機能を利用できますか?

24
user456885

いいえ、そうです。マルチバイト文字列に対してシングルバイト文字列関数を使用すると、予期しない結果が生じる可能性があります。代わりに マルチバイト文字列関数 を使用します。例: mb_ereg_replace または mb_split

$string = mb_ereg_replace('"', '\\"', $string);
$string = implode('\\"', mb_split('"', $string));

Edit分割結合バリアントを使用したmb_replaceの実装は次のとおりです。

function mb_replace($search, $replace, $subject, &$count=0) {
    if (!is_array($search) && is_array($replace)) {
        return false;
    }
    if (is_array($subject)) {
        // call mb_replace for each single string in $subject
        foreach ($subject as &$string) {
            $string = &mb_replace($search, $replace, $string, $c);
            $count += $c;
        }
    } elseif (is_array($search)) {
        if (!is_array($replace)) {
            foreach ($search as &$string) {
                $subject = mb_replace($string, $replace, $subject, $c);
                $count += $c;
            }
        } else {
            $n = max(count($search), count($replace));
            while ($n--) {
                $subject = mb_replace(current($search), current($replace), $subject, $c);
                $count += $c;
                next($search);
                next($replace);
            }
        }
    } else {
        $parts = mb_split(preg_quote($search), $subject);
        $count = count($parts)-1;
        $subject = implode($replace, $parts);
    }
    return $subject;
}

パラメータの組み合わせに関しては、この関数はシングルバイトstr_replaceのように動作する必要があります。

28
Gumbo

コードは、UTF-8やEUC-TWなどのsaneマルチバイトエンコーディングでは完全に安全ですが、broken Shift_JIS、GB *などのコードでは危険です。これらのレガシーエンコーディングを安全に使用するには、頭痛とオーバーヘッドがすべて伴うため、UTF-8のみをサポートすることをお勧めします。

最初にmb_regex_encoding()で文字セットを指定することにより、mb_ereg_replaceを使用できます。あるいは、UTF-8を使用する場合は、u修飾子とともにpreg_replaceを使用できます。

3
reko_t