13

ユーザー定義の小さな正規表現をテスト用に送信できるようにしたいと考えています。ただし、暴走したサーバーの使用からより悪質なeval()使用まで、考慮すべき多くの問題があります。

私の知る限り、次のコードで考えられるすべての問題を処理しました。私が思いもよらなかった攻撃ベクトルはありますか? (私が知っているかなり素朴な質問)

function testRegex($regex)
{
    // null character allows a premature regex end and "/../e" injection
    if (strpos($regex, 0) !== false || ! trim($regex)) {
        return false;
    }

    $backtrack_limit = ini_set('pcre.backtrack_limit', 200);
    $recursion_limit = ini_set('pcre.recursion_limit', 20);

    $valid = @preg_match("~$regex~u", null) !== false;

    ini_set('pcre.backtrack_limit', $backtrack_limit);
    ini_set('pcre.recursion_limit', $recursion_limit);

    return $valid;
}


$regexes = array(
    "InvalidRegular)Expression",
    '',
    '\w+',
    '\/\w+/',
    'foo[bar]*',
    '\/\x00known/e' . chr(0x00) . chr(0),
    'known~e' . chr(0),
    'known~e' . chr(0x00),
    '[a-z]+',
    '\p{Lu}+',
);


foreach($regexes as $regex) {
    var_dump($regex, testRegex($regex));
}

null-byteインジェクションの例を見たい場合:

$user_regex = '.+~e' . chr(0);
$user_match = 'system("whoami")';

var_dump(preg_replace("~$user_regex~u", $user_match, 'foo'));
4

2 に答える 2

8

明らかに、文字列が有効な正規表現であるかどうかをテストする唯一の方法は、それをコンパイルすることです (これは、一致する関数のいずれかを呼び出すときに行われます)。

追加したヌルバイト保護は、5.4 以降では実際には必要ありません。これは、リーダーミドル、およびエンディングで既にチェックが行われているためです。特に後者は、このバグを修正するための比較的最近のコミット(2011 年)です。

バックトラックと再帰の制限を低く設定することは、サンドボックスとしては十分です。おそらく、最大長も確認できます。

とはいえ、この特定のソリューションでは/s、 、/i/m;などの修飾子を使用する機能は提供されません。おそらく、それは現時点でのあなたの主な関心事ではなく、むしろ考える材料です :)

于 2014-02-18T02:20:07.747 に答える
1

{expression} のようなものを入力してから、preg_replace() を使用するように指示できます。そうすれば、彼らはあなたが許可したものだけを使用します。

于 2014-03-09T14:00:43.613 に答える