目次
WAFとは
WAFとは Web Application Firewall のことを言います。WAFとは、企業のWebサイトに対してアクセスの内容までチェックするファイアウォールのことを言います。一般的なファイアウォール(Firewall)はIPアドレス、ポート番号、プロトコルを見ていますが、WAFはHTTP/HTTPSの中身まで見ています。
具体的には、HTTP/HTTPSの以下の内容を見ています。
- URL
- ヘッダ(Header)
- クエリストリング(Query String)
- リクエストボディ(POSTの中身)
Webリクエストの中身まで見ていることになりますが、主に SQLインジェクション や クロスサイトスクリプティング など、アプリケーション層の脆弱性を突く攻撃を防ぎます。ちなみに一般的な企業は WordPress などを利用して企業サイトを構築しています。その後企業が成長するにつれて WordPress では企業サイトの要件などが満たせなくなると、WordPress を止めてオリジナルのサイトに移行していきます。DBも独自にテーブルを設計してカスタマイズしていきます。ひたすらカスタマイズせずにWordPressを使い続けるという選択肢もありますが、大体組織が大きくなりお金が絡んでくるとオリジナルへ移行します。
しかしこの移行がセキュリティホールとなり、 SQLインジェクション や クロスサイトスクリプティング などで顧客情報がごっそりと漏洩することがあります。サイトをインターネットに公開すると定期的に攻撃が来るものと思わなければいけません。
AWSで企業サイトを構築している場合はAWS WAFを利用することができます。今回はこの AWS WAF について解説したいと思います。
AWSはどのリソースタイプに設定できるか
AWS WAFはAWSのリソースに設定(統合)できます。まずはどのリソースタイプに設定できるか確認します。以下のリソースで、当たり前ですがインターネットにさらされるリソースタイプです。S3バケットもインターネットに晒されますが、基本的にS3バケットをインターネットに公開する際は CloudFront を経由する前提だと思うので S3 単体では WAF を適用できないようです。
- CloudFront
- API Gateway
- ALB(Application Load Balancer)
- AppSync GraphQL API
- Cognito
- App Runner
- Verified Access インスタンス
- Amplify
保護パックとは
AWS WAFを開始する際に「保護パック(ウェブ ACL)を作成」ボタンが表示されます。

保護パックとは何でしょうか。カッコ書きでウェブ ACLと記載があるので従来の WebACL と考えて良さそうです。私もいつの間にか「保護パック」の文言に変わっていたので何だろうと思いました。今後はWeb ACLではなく 保護パック で行くようです。ここら辺の構成を躊躇なく?変更もしくは更新するところはさすがAWSといったところです。
しかし実際現場では「保護パック」という呼び方はあまり浸透していないので従来通りWebACLと呼んだ方が伝わりそうです。そのうち「保護パック」という用語もさらっと消えそうな予感も。
保護パック で、保護されたリソース(CloudFrontなど)が応答するすべての HTTP(S) ウェブリクエストをきめ細かく制御できます。
すべての HTTP(S) ウェブリクエストをきめ細かく制御できるとは?
「保護パック で、保護されたリソース(CloudFrontなど)が応答するすべての HTTP(S) ウェブリクエストをきめ細かく制御できます。」とあります。
すべての HTTP(S)メソッド/Path/Query/Cookie/Headers/Body/JSON Body/サイズなどでしょうか。とりあえず全部ということですね。全部のウェブリクエストをきめ細かく制御できるということで以下の制御が可能です。
ちなみにウェブリクエストとは、Wegブラウザ(Google Chromeなど)がWebサーバーに対して、Webページやデータなどの情報を要求することです。ウェブリクエストを送るとWebサーバーがWebページやデータを返してくれます。
この全てのウェブリクエストに対して、許可したりブロックしたり、様々なルールを組み合わせて制御することができます。組み合わせでかなり複雑な制御ができます。シンプルな制御はAWS管理画面上からGUIで可能ですが、複雑な制御になるとJSONで記載してコピペすることになります。
WAF WebACL の作成手順
保護パック(Web ACL)を作成する際にアプリカテゴリを選択します。

以下のカテゴリがあります。
- コンテンツ及び公開システム
- e コマースおよび取引プラットフォーム
- エンタープライズおよびビジネスアプリケーション
- API および統合サービス
- メディアおよびファイル処理
- その他
どれを選択しても後から自由に変更できます。最初の選択で固定されるわけではありません。
ちなみに選択する目途や観点としては以下のようになっています。
■コンテンツ及び公開システム
静的/動的サイトなど広く一般公開するWeb。例: 企業サイトなど。
■e コマースおよび取引プラットフォーム
決済・カート・会員画面など個人情報の入力が多く攻撃のターゲットにされやすいサイト。
例: EC、クレジット決済、会員登録/ログインなど。
フォーム/クッキー/クエリなどを重点的に構成されている。
■エンタープライズおよびビジネスアプリケーション
社内向け・業務SaaSなど。
■API および統合サービス
APIエンドポイント中心。
■メディアおよびファイル処理
画像/動画/ファイルのアップロード・変換・配信が中心。
例: 画像アップロード、動画アップロードなど。
■その他
上記に当てはまらない、もしくは自分で一から組みたい場合。
アプリケーションフォーカス
アプリケーションフォーカスは以下の3つが選択できます。特に要件がなければ「APIとウェブの両方」を選択します。

「保護するリソースを選択」で「リソースを追加」ボタンをクリックします。

「CloudFront リソースまたは Amplify リソースを追加」を選択します。

初期の保護を選択します。以下の3つのルールから選択できます。
- お客様のために推奨されるルール
- 重要ルール
- AWS WAF が提供するすべての保護から独自のパックを構築

デフォルトのルールアクションを選択します。いきなり WAF でブロックするのではなく、まずは Count で WAF ルールの挙動を確認する場合は、「すべてを Count アクションに設定」を選択します。本番環境の場合は、まずは Count アクションから動作確認をした方が良いと思います。
- Count アクションと Block アクションに推奨のデフォルトを使用する
- すべてを Count アクションに設定

デフォルトで「レート制限」の設定が入っています。下図のような設計ですが、特に極端な設定ではないのでこのままで良いと思います。

ブロックしたい IP アドレスを設定します。

ブロックしたい国を選択します。下図はデフォルトでブロックされている国です。確かに国家としてクラッキングをしていそうな国々ですね。

最後にログを取得する場合はロググループを選択して「保護パック(ウェブ ACL)を作成」ボタンをクリックします。CloudWatch Logs ロググループは、「aws-waf-logs-xxx」の形式で作成しておくと自動的に表示されます。

作成されました。

各設定値について
SampledRequestsEnabled
trueにするとルールにマッチしたリクエストの一部(サンプリング)が見れます。サンプリングなので全部が見れるわけではありません。あくまでもWAFの管理画面上からサンプルとして確認ができるということです。なので検証でちょっと確認しつつ運用したい場合にはtrueにすると良いです。
マネージドルールグループ
よく利用するマネージドルールグループは以下の2つになります。
aws-managed-common は以下のようなおかしな(怪しい)リクエストについて取り扱っています。
- 不正・おかしな HTTP メソッド
- 異常に長い URL / ヘッダ / クエリ
- 不正な / あり得ないヘッダ
- 明らかに怪しい User-Agent / クライアント
- 既知の悪用パターンっぽいリクエスト全般
複雑なルールはJSONで記述する
WAFのルールを作成する場合、シンプルなルールの場合はAWS管理画面(GUI)から作成できますが、複雑なルールはJSONが作った方が管理しやすいです。というよりもネストが深く複雑なルールを作成すると次回からGUIではなくJSONエディタでしか更新や修正ができなくなります。そのため、最初からJSONでルールを記述するのも良いと思います。
ちなみにGUIでルールを作成する場合はネストレベルは1レベルのみサポートされます。そのため複雑なルールを作成する場合は最初からJSONエディタを利用した方が良いでしょう。
WAFのルールはクセがあります。とは言っても基本的には以下の2つで構成されています。
- ルールステートメント → ウェブリクエストを検査する方法を定義する
- ルールアクション → ウェブリクエストがルールで定義された条件に一致する場合に、 ウェブリクエストの処理を指示する
ルールステートメントは複雑に組み合わせることも出来ます。AND、OR、NOTステートメントが利用できます。
ルールステートメント
ルールステートメントが一番の難関です。アクションはBlockやAllow、Countなど一目見れば分かります。ステートメントでいかにWAFでやりたいことを実現するかを表現します。
インターネット経由で膨大な数のウェブリクエストが届きます。WAFはルールステートメントに一致するとみなされた場合に、指定されたアクションを実施します。
例えば『中国や北朝鮮、ロシアなどのIPアドレスはブロックする』などです。デフォルトはAllowで中国や北朝鮮、ロシアなどのIPアドレスをブロックするIP setsにしてルールステートメントでロジックを作ります。条件をより複雑にするために、すぐにブロックせずに一旦ラベリングをして2段階目の検査、3段階目の検査でラベルとウェブリクエストの内容をチェックしてAllowやBlockすることもできます。
一度に全部のステートメントを入れ込み複雑なステートメントにする必要はなくて、一旦ラベリングをしてから『Aというラベルがついていて、且つヘッダーに〇〇がない場合はBlockする』などのロジックも可能です。
ルールアクション
ルールアクションはルールで定義された条件に一致した場合にどのような処理をするのかを決めるものです。
以下のアクションがあります。
- Allow → リクエストをAWSリソースに転送することを許可します。終了アクションです。
- Block → リクエストをブロックします。
- Count → リクエストをカウントします。許可もブロックもしません。終了もしません。
- CAPTCHA and Challenge → このアクションは CAPTCHA パズルとサイレントチャレンジを表示させて、ボットからのものではないことを確認する場合に利用します。
Countは何をしているのか
実際にCountは何をしているのでしょうか?
- Web ACL やルールのCloudWatchメトリクスカウントを加算していく
- ログにルールステートメントにマッチしたことを残す
- ラベリングをする
Countを利用するケースとしては以上になりますが、更にWAFの動作テストでもいきなりAllowやBlockを試すのではなく一定期間テストのためにCountを設定することもあります。実際にWAFを運用してみると誤検知・誤検出があります。本番環境の場合はサービスに影響が出るので事前のテストの為にもCountを有効活用できます。
■参考サイト
AWS WAF のカウントルールアクションのメトリクスとログはどのようにフォーマットされていますか?
JSONでルールを作成する際の基本
JSONでルールを作成する際の基本的なパターンをまとめました。このパターンを知っておくと長いJSONルールを見ても混乱しなくなると思います。
まずは、1つのルールは1つのif文だと考えます。1つのルールは以下のような構造になっています。
{
"Name": "rule-name",
"Priority": 10,
"Action": { "Block": {} }, // or { "Allow": {} }, { "Count": {} }, "OverrideAction"
"Statement": { ... }, // 条件(if 文の中身)
"VisibilityConfig": { ... } // メトリクスやサンプルログ設定
}
ステートメント(Statement)には条件の内容を書きます。「もしステートメントの条件が true なら Action を実行する」といった感じです。例えば「もし中国・北朝鮮・ロシアからアクセスが来たらブロックする」などです。
このステートメント(Statement)の書き方ですが、”Statement”: { … } の中は以下のようなステートメントから始まります。
- AndStatement
- OrStatement
- NotStatement
- GeoMatchStatement
- ByteMatchStatement
- RegexMatchStatement
- LabelMatchStatement
- ManagedRuleGroupStatement(マネージドルール)
Terraformで複雑なルールを作成する場合はJSONファイルを別だしにする
Terraform のプロバイダの問題でネストが深く複雑なルールを作成するとエラーになります。その場合は、複雑なルールを記述したJSONファイルを外出しにするとTerraformでエラーが出ません。
TerraformのAWSプロバイダとはTerraformからAWSに命令を出すためのドライバーです。Terraformでリソースを定義してそれをAWS上でリソースを作成します。いわばTerraformとAWSの橋渡しをしているのがプロバイダになります。実際にAWSにどのようなリソースを作成するのかはAPIで命令しています。プロバイダはTerraformのコードを見てどのようなAPIでどのようなパラメータでリソースを作るのか整えて実行しています。
しかしAWSプロバイダが膨大なAWSサービスの最新まで含めてすべて網羅しているわけではありません。AWSから新サービスが出た瞬間にAWSプロバイダでも更新されているということは無理です。また出来ないこともあります。
WAFの場合はネストが深く複雑なルールはAWSプロバイダが対応していないので、TerraformでWAFを運用するなら最初からJSONファイルを外出しにする必要があります。もちろん、将来的には外出しにしなくてもよくなるかもしれませんが、WAFのリソースブロックに全てのルールを入れるとかなりコードが見にくくなるので、やはり外出しにした方が運用・管理がしやすくなると思います。
JSONファイルを外出しにするコード例
resource "aws_wafv2_web_acl" "dev-waf-web-acl" {
name = "dev-waf-web-acl"
description = "dev environment waf web acl"
provider = aws.us_east_1
scope = "CLOUDFRONT"
default_action {
allow {}
}
# JSON をそのまま渡す
rule_json = jsonencode([
# 最初に IP ブロック
jsondecode(file("${path.module}/00-allow-ipset.json")),
# マネージドルール
jsondecode(file("${path.module}/10-aws-managed-sqli.json")),
jsondecode(file("${path.module}/11-aws-managed-common.json")),
# カスタムルール
jsondecode(file("${path.module}/20-custome-rule-1.json")),
jsondecode(file("${path.module}/21-custome-rule-2.json"))
])
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "dev-waf-web-acl"
sampled_requests_enabled = true
}
tags = {
Name = "dev-waf-web-acl"
}
}
例:中国、北朝鮮、ロシアからのアクセスを拒否する
大規模なウェブサイトを運用している場合は、これは必須と言ってよいでしょう。
GeoMatchStatement(地理的一致ルールステートメント)を利用できます。AWS WAF は、国際標準化機構 (ISO) 3166 規格の alpha-2 の国と地域のコードを使用しているので、以下のように「CN」「KP」「RU」と記載します。国コードはWikipediaで確認できます。ISO 3166-2
コード例
{
"Name": "block-cn-kp-ru",
"Priority": 0,
"Action": {
"Block": {}
},
"Statement": {
"GeoMatchStatement": {
"CountryCodes": [
"CN",
"KP",
"RU"
]
}
},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "block-cn-kp-ru"
}
}
WAFの運用は大変
WAFの運用は大変です。しかしセキュリティは大事です。企業の売上や評判を左右します。しかしもしWAF担当に選ばれた場合、ポジティブに考えると自分のITエンジニアの経歴にWAFの設計・構築・運用などが加わるので将来的には非常によいスキルを取得するチャンスとみてよいでしょう。セキュリティエンジニアの単価は高いです。以前、所属していた大手のSES企業のセキュリティエンジニアの月単価は400万円でした。今のご時世、もっと単価は上がっているかもしれません。独立しても引く手数多だと思います。
しかし実際にはWAFの運用は大変です。特に興味がないと面白みがないかもしれません。しかしWAF運用に面白みを感じたら将来的にセキュリティエンジニアとしてのキャリアを進めると思います。
まずは様々なウェブリクエストに対して何を許可したいのか何を許可したくないのかを開発側と十分コミュニケーションを取って設計していきます。両社の協力が必要です。
その後ルールステートメントのロジックを考えてテストをしてログを確認して更にルールを調整してきます。大量のログを定期的に見て誤検知・誤検出がないのかをひたすら確認して問題があればロジックを更新するという作業を繰り返しやっていくことになります。
どうせならSQLインジェクションやクロスサイトスクリプティングなども基礎から学習するとより理解度が深まりモチベーションも上がると思います。
コメント