アンチパターン: RegularExpressionProtection ポリシーで「欲張り」な数量子を使用する

RegularExpressionProtection ポリシーは正規表現を定義します。正規表現は、ランタイムに入力パラメータまたはフロー変数に対して評価されます。このポリシーは通常、コンテンツに対する脅威(SQL インジェクション、JavaScript インジェクションなど)からの保護、あるいは不正な形式のリクエスト パラメータ(メールアドレス、URL など)のチェックに使用します。

正規表現は、リクエストパス、クエリ パラメータ、フォーム パラメータ、ヘッダー、XML 要素(XPath を使用して定義された XML ペイロード内)、JSON オブジェクト属性(JSONPath を使用して定義された JSON ペイロード内)に対して定義できます。

次に、RegularExpressionProtection ポリシーを使用して、SQL インジェクション攻撃からバックエンドを保護する例を示します。

<!-- /antipatterns/examples/greedy-1.xml -->
    <RegularExpressionProtection async="false" continueOnError="false" enabled="true"
      name="RegexProtection">
        <DisplayName>RegexProtection</DisplayName>
        <Properties/>
        <Source>request</Source>
        <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
        <QueryParam name="query">
          <Pattern>[\s]*(?i)((delete)|(exec)|(drop\s*table)|
            (insert)|(shutdown)|(update)|(\bor\b))</Pattern>
        </QueryParam>
    </RegularExpressionProtection>
    

アンチパターン

デフォルトの数量子(*+?)は、「欲張り(greedy)」な性質を持ちます。つまり、最初から可能な限り最長の文字列を一致させようとします。一致する文字が見つからなければ、徐々にバックトラックを行い、パターン一致を試みます。結果的にパターンに一致する文字列が極端に短い場合は、欲張りな数量子を使用することで、必要以上に長い処理時間がかかる可能性があります。これは、大きなペイロード(数十 KB、数百 KB の規模)であればなおさらです。

次の正規表現の例では、欲張りな演算子 .* のインスタンスをいくつか使用します。

<Pattern>.*Exception in thread.*</Pattern>

この例では、RegularExpressionProtection ポリシーは最初に、可能な限り最長の文字列(文字列全体)を一致させようとします。一致する文字が見つからなければ、徐々にバックトラックを行います。一致文字列がペイロードの先頭または中心に近い位置にある場合は、欲張りな数量子(.* など)を使用することで、「無欲(reluctant)」な数量子(.*? など)、または、あまり一般的ではないながら「独占的(possessive)」な数量子(.*+ など)を使用する場合に比べ、より多くの処理時間と処理能力を費やす可能性があります。

無欲な数量子(X*?X+?X?? など)は、ペイロードの先頭から 1 文字ずつ一致を試み、徐々に文字を追加していきます。独占的な数量子(X?+X*+X++ など)は、ペイロード全体の一致を一度だけ試行します。

上述のパターンを、次のサンプル テキストに適用するとします。

Hello this is a sample text with Exception in thread
    with lot of text after the Exception text.

この場合は、欲張りな .* の使用は効率が悪すぎます。パターン .*Exception in thread.* は、一致までのステップ数が 141 となります。代わりに、無欲な数量子による .*?Exception in thread.* パターンを使用すると、ステップ数はわずか 55 で済みます。

影響

RegularExpressionProtection ポリシーで、ワイルドカード(*)などの欲張りな数量子を使用すると、次の結果が生じる可能性があります。

  • あまり大きくないペイロード サイズ(最大 1 MB)の場合、API リクエスト全体のレイテンシが大きくなります。
  • RegularExpressionProtection ポリシーの実行完了までの時間が長くなります。
  • ペイロードの大きな(1 MB 超)API リクエストの場合、Edge Router で事前定義したタイムアウト時間が経過すると、504 ゲートウェイ タイムアウト エラーが生じ、リクエストが失敗します。
  • 処理量が大きいため、Message Processor の CPU 使用率も高くなり、他の API リクエストにまで影響が及ぶ可能性があります。

ベスト プラクティス

  • RegularExpressionProtection ポリシーで正規表現を使用する場合は、.* などの欲張りな数量子の使用を避けます。代わりに、可能であれば無欲な数量子(.*? など)や独占的な数量子(.*+ など。あまり一般的ではない)を使用します。

関連情報