こんにちは。X(クロス)イノベーション本部 ソフトウェアデザインセンター セキュリティグループの耿です。
AWS WAF には AWS マネージドルールが複数提供されており、利用することで AWS が定めた条件に一致するリクエストをブロックしてくれます。各マネージドルールグループには、複数の個別のルールが含まれています。例えばコアルールセット (CRS) マネージドルールグループには、v1.6 時点で 22 個の個別ルールが含まれています。
マネージドルールグループの個別ルールには、アプリケーションによっては条件が厳しすぎるものもあります。例えば以下の個別ルールによってリクエストをブロックして欲しくない場合があるかもしれません。
マネージドルール名 | 検出条件 |
---|---|
SizeRestrictions_BODY | リクエストボディサイズが 8 KB を超える場合はブロック |
EC2MetaDataSSRF_BODY | リクエストボディに「localhost」「127.0.0.1」の文字列が含まれている場合はブロック(*注1) |
GenericLFI_BODY | リクエストボディに「../../」の文字列が含まれている場合はブロック、など |
(*注1) 筆者が確認した条件であり、公式のアナウンスではありません。また他にも条件があるかもしれません。
マネージドルールがアプリケーションの要件に合わない時は、個別のルールのアクションを Count
にオーバーライドすることができます。
しかしこれではあらゆる状況においてそのルールによるブロックが無効化されてしまい、マネージドルールを使っている効果が薄れてしまいます。そうではなく、「特定の条件においてのみ」マネージドルールのアクションを Count
に変更したい場合があると思います。こちらでも紹介されているような方法であり、AWS WAF のラベルを利用して実現します。
マネージドルールに条件を追加する仕組み
まず、特定の条件において「のみ」マネージドルールのアクションを変更するための仕組みを説明します。
マネージドルールの判定条件に一致した場合、一致した目印として特定の「ラベル」がリクエストに付与されます。ルールアクションを Count
にオーバーライドした場合も、ブロックはされなくなりますが「ラベル」は Block
の時と変わらず付与されます。例えば EC2MetaDataSSRF_BODY
ルールに一致した場合は awswaf:managed:aws:core-rule-set:EC2MetaDataSSRF_Body
というラベルが付与されます。付与されたラベルは Web ACL 内の後続のルールからも確認することができます。
マネージドルールグループの後に評価される自作ルールを追加し、Statement に「(Count
にオーバーライドした)マネージドルールに一致した場合に付与されるラベル」と「ブロックを有効にしたい条件」を AND 条件で評価させることで、「特定の条件においてのみ」アクションを Count
に変更することができます。例えば、リクエストの URI パスが /api/*
であれば EC2MetaDataSSRF_BODY
ルールによるブロックを無効にしたいが、他の URI パスではそのまま有効にしたい場合、次の2つの Statement を AND 条件で繋げ、アクションを Block
とした自作ルールを追加します。
- リクエストに「awswaf:managed:aws:core-rule-set:EC2MetaDataSSRF_Body」ラベルがある
かつ - URIパスが
/api/*
ではない (NotStatement)
場合に、Block
ここからは、これを実際にマネジメントコンソールで試してみます。
(準備)ALBの作成
WAF Web ACL を関連付けるための ALB を作成し、固定レスポンスを返すようにします。
WAF Web ACL 作成
WAF Web ACL を作成し、ALB に関連付けます。
「Create web ACL」をクリック
Web ACL の名前を入力し、前のステップで作成した ALB を関連付け、「Next」をクリック
「Add managed rule groups」をクリック
「AWS managed rule groups」にある「Core rule set」のスイッチをオン
あとはデフォルト設定のまま Web ACL の作成を完了させます。
WAFの動作確認①:マネージドルールの動作確認
WAF Web ACL が関連付けられた状態の ALB にリクエストを送ってみます。
ボディに何も含まれていない POST リクエストは、ブロックされることなく ALB に設定した固定レスポンスが返ってきます。
しかしリクエストボディに「localhost」を含めると、WAF にブロックされ 403 が返されます。
個別ルールのアクションのオーバーライド
EC2MetaDataSSRF_BODY
ルールのアクションを Count
にオーバーライドし、リクエストボディに「localhost」があってもブロックされないようにしていきます。
先ほど作成した WAF Web ACL に追加したマネージドルールをチェックし、「Edit」を選択
EC2MetaDataSSRF_BODY
ルールアクションを Override to Count
に変更し、「Save rule」をクリック
次の画面でも「Save」をクリック
WAFの動作確認②:マネージドルール無効化の確認
再びリクエストボディに「localhost」を含めるリクエストを送信すると、今度はブロックされずに固定レスポンスが返ってきます。
現在、あらゆる状況において EC2MetaDataSSRF_BODY
ルールによるブロックが無効化されている状態です。次のステップからは「URI パスが /api/
から始まる場合に限り、ブロックを無効化する」ようにカスタマイズしていきます。
自作ルールの追加
「Add my own rules and rule groups」をクリック
ビジュアルエディタで次のように Statement を組み立て、「Add rule」をクリック
優先順位がマネージドルールグループよりも後ろであることを確認し、「Save」をクリック
WAFの動作確認③:自作ルールの確認
再びリクエストボディに「localhost」を含めるリクエストを送信すると、今度はブロックされました。
しかし、リクエスト URI を「/api/hello」とすると、ブロックされずに通過しました。
以上で、マネージドルールグループの個別ルールに条件を追加することができました。
より複雑な条件の場合
以上はシンプルな条件について確認しましたが、条件が複雑な場合の自作ルールの組み方を簡単に説明します。例として以下の場合です。
- マネージドルールグループの
EC2MetaDataSSRF_BODY
ルールとGenericLFI_BODY
ルールを対象にしたい - リクエストがこれらのルールに一致した場合、「リクエスト URI が
/api/*
」かつ「content-type
ヘッダーがapplication/json
」の場合はブロックされないようにしたい。それ以外の場合はブロックしたい
このような自作ルールは次のように実現できます。
今のところ AND
条件や OR
条件が多重になるルールはビジュアルエディタで作成できませんので、JSON エディタに切り替えてルールを編集することになります。
例に示した複雑な条件の自作ルールは、以下のような JSON で作れます。
{ "Name": "custom-body-block", "Priority": 1, "Statement": { "AndStatement": { "Statements": [ { "OrStatement": { "Statements": [ { "LabelMatchStatement": { "Scope": "LABEL", "Key": "awswaf:managed:aws:core-rule-set:EC2MetaDataSSRF_Body" } }, { "LabelMatchStatement": { "Scope": "LABEL", "Key": "awswaf:managed:aws:core-rule-set:GenericLFI_Body" } } ] } }, { "NotStatement": { "Statement": { "AndStatement": { "Statements": [ { "ByteMatchStatement": { "SearchString": "/api/", "FieldToMatch": { "UriPath": {} }, "TextTransformations": [ { "Priority": 0, "Type": "NONE" } ], "PositionalConstraint": "STARTS_WITH" } }, { "ByteMatchStatement": { "SearchString": "application/json", "FieldToMatch": { "SingleHeader": { "Name": "content-type" } }, "TextTransformations": [ { "Priority": 0, "Type": "NONE" } ], "PositionalConstraint": "EXACTLY" } } ] } } } } ] } }, "Action": { "Block": {} }, "VisibilityConfig": { "SampledRequestsEnabled": true, "CloudWatchMetricsEnabled": true, "MetricName": "custom-body-block" } }
さいごに
AWS WAF マネージドルールグループの個別ルールの適用条件を、ラベルと自作ルールを使ってカスタマイズする方法を試しました。最初は難しそうに見えるかもしれませんが、理屈を理解すると柔軟にマネージドルールをカスタマイズできるようになるので、AWS WAF をより使いこなしたい方はぜひ試してみてください。
私たちは同じチームで働いてくれる仲間を大募集しています!たくさんのご応募をお待ちしています。
セキュリティエンジニア執筆:@kou.kinyo、レビュー:@wakamoto.ryosuke
(Shodoで執筆されました)