はじめに ── 同じWAFが、SQLiは弾くのにIDORは素通しする
数年前の私は、「AWS WAF とセキュリティグループを入れたんだから、もう安全だろう」と本気で思っていました。インフラで境界を固めた、だからアプリ側の対策は後回しでいい、と考えていたのです。第1回で扱った IDOR(他人の ID を指定して他人のデータを見てしまう脆弱性)も、WAF が止めてくれるものだと思い込んでいました。
その思い込みは、ある実験で崩れました。同じ1台の WAF に、宛先も認証済みセッションも固定したまま、2種類のリクエストを投げます。
- (A) SQL インジェクションのペイロードを送ると、WAF は
403 Forbiddenで弾きました。 - (B) 認証済みのまま ID だけ他人のものに書き換えた、ごく普通の
GETを送ると、200 OKで他人のデータが返ってきました。
同じ WAF です。攻撃の「形」をしている (A) は止めたのに、正当な「形」の (B) は素通しにしました。ここでようやく気づきました。その WAF、「誰がそのデータを見てよいか」まで判断してくれてはいなかったのです。
この記事は、そんなちょっと前の私に向けて書きます。
想定読者:
- AWS WAF やセキュリティグループを導入して「インフラで境界を固めたから大丈夫」と考え、アプリ側の認可(特にオブジェクト単位)を後回しにしていた Web アプリ開発者
- WAF が何を止めて何を通すのか、L3/4(セキュリティグループ)と L7(WAF)の違いをあまり意識していなかった人
この記事のゴールは、境界防御(WAF / セキュリティグループ)とアプリの認可の「線引き」を持ち帰ることです。何が境界で防げて、何が境界では防げずアプリでしか防げないのか。その線を引けるようになるのが到達点です。
本記事は社内セキュリティ勉強会シリーズ(全6回)の第5回です。ロードマップは次のとおりで、今回は境界に重心を置きます。
- 第1回: 認証・認可(IDOR)
- 第2回: インジェクション・SSRF
- 第3回: XSS・CSRF・セッション
- 第4回: 暗号・シークレット
- 第5回: ネットワーク・WAF(本記事 = 現在地)
- 第6回: ログ・追跡
第2回では「入口は WAF・ネットワーク境界で塞ぐ、詳しくは第5回で」、第4回では「暗号の入口である SSRF などは境界・WAF で、第5回で」と送りました。その伏線を、この記事で回収します。当日の発表スライドも公開しているので、あわせてご覧ください。
先に結論(この記事で伝えたい3点)
細かい説明に入る前に、いちばん伝えたいことを3つ先に出します。
- 境界(WAF / セキュリティグループ)は通信の形 = IP・ポート・既知パターンを判断する。
- 中身の正当性(認可)は境界では判断できず、アプリでしか塞げない。
- 脅威ごとに受ける層を決め、多層で守る。
この3点を、以降の本文でほどいていきます。冒頭の「SQLi は弾くのに IDOR は素通し」という現象は、この3点がわかれば当然の帰結として腑に落ちます。
この記事で扱うこと・扱わないこと
対象技術とバージョンは次のとおりです。
- AWS WAF(v2): Web ACL を CloudFront / ALB / API Gateway などに関連付ける L7 の Web アプリケーションファイアウォール
- Amazon VPC: セキュリティグループ(ステートフル・ENI 単位・L3/4)/ ネットワーク ACL(ステートレス・サブネット単位)
-
Amazon EC2 IMDS: インスタンスメタデータサービス(
169.254.169.254) - Laravel 13.x(新規)+ FuelPHP 1.x(レガシー)、言語は PHP
- OWASP Top 10: A01:2021 Broken Access Control
- CCT 日本語 eBook: Module 07(Network Security Controls – Technical Controls)
- WAF の検査サイズ上限などの数値は 2026年7月時点の現行値です(AWS が将来変更しうるため、実際の設計時は公式ドキュメントで再確認してください)
範囲を絞るため、次の項目は本記事では深追いしません。いずれも重要ですが、1記事に詰め込むと焦点がぼやけます。
- TLS / HTTPS が前提であること自体は当然として、暗号の中身には踏み込みません(第4回で扱います)。
- IDOR / 認可の具体的な実装コード(オブジェクト単位の認可)は第1回で扱ったので、本記事では再解説せず結線だけします。
- SQLi のプレースホルダ・SSRF の URL 検証・IMDSv2 の実装は第2回、XSS の出力エスケープの実装は第3回で扱っています。
- 境界を素通りした攻撃の検知・追跡(WAF ログ / VPC フローログ / GuardDuty)は第6回で扱います。
ここでは「境界とアプリ認可の線引き」の一点に絞ります。
境界防御は「通信の形」を判断する
まず、WAF とセキュリティグループが何を判断する道具なのかを正しく揃えます。ここが揃うと、冒頭の「SQLi は弾くのに IDOR は素通し」がなぜ起きるのかが構造で見えてきます。
境界防御とは、信頼できない外部と内部を分け、入口で通信を制限する仕組みです。ただし境界は最初の関門であって、唯一の関門ではありません。図のように、境界の内側にはネットワーク分離、アプリの認可、データの暗号と、層が続きます。
CCT の教材でも、ファイアウォールの機能は「流れる全トラフィックをルールセットの基準で検査し、明示的に許可されたトラフィックのみ通し、他はデフォルトで拒否する。各パケットを検査して宛先へ送るか判定し、侵入を記録する」と説明されています(出典: CCT eBook 書籍825/PDF836)。ファイアウォールにはいくつか種類があり、機能する層が異なります(出典: CCT eBook 書籍791・806-811/PDF802・817-822)。
| ファイアウォールの種類(CCT) | 機能する層 |
|---|---|
| パケットフィルタリング | IP層 / トランスポート層(L3/4) |
| ステートフルマルチレイヤインスペクション | 複数層 |
| サーキットレベルゲートウェイ | セッション層 |
| アプリケーションレベルゲートウェイ | アプリケーション層(L7) |
この表の両端、パケットフィルタ(L3/4)とアプリケーションレベルゲートウェイ(L7)が、それぞれ AWS のセキュリティグループと AWS WAF に対応します。順に見ていきます。
セキュリティグループ = L3/4 のパケットフィルタ
CCT のパケットフィルタリングファイアウォールは、TCP/IP の IP 層(ネットワーク層)とトランスポート層、いわゆる L3/4 で機能し、送信元/宛先の IP アドレス・ポート・プロトコルなどでパケットを許可またはドロップします(出典: CCT eBook 書籍806-807/PDF817-818)。判断材料は通信の「形」だけです。
これに対応する AWS の実体がセキュリティグループです。EC2 インスタンスや ENI といったリソースに付く仮想ファイアウォールで、次の性質を持ちます(出典: https://docs.aws.amazon.com/vpc/latest/userguide/vpc-security-groups.html)。
- ステートフル: 許可した通信の戻りは、インバウンドルールに関係なく自動で許可される
- 許可ルールのみを持つ(拒否ルールは書けない)
- リソース(ENI)単位で適用する
どちらも見ているのは IP・ポート・プロトコル、つまり L3/4 の「形」だけで、HTTP の中身は見ていません。
AWS WAF = L7 の門番
CCT のアプリケーションレベルゲートウェイは、OSI モデルのアプリケーション層(L7)で機能し、http:post や get などのアプリケーション層コマンドを検査します(出典: CCT eBook 書籍811/PDF822)。
これに対応するのが AWS WAF です。Web ACL を CloudFront ディストリビューション・Application Load Balancer・API Gateway・AppSync などに関連付けて HTTP / HTTPS リクエストを検査し、一致すれば Allow / Block(HTTP 403)/ Count / CAPTCHA・challenge のいずれかを返します(出典: https://docs.aws.amazon.com/waf/latest/developerguide/what-is-aws-waf.html)。
SQLi や XSS のような既知の攻撃パターンは、AWS Managed Rules で検知・ブロックできます。マネージドルールには Core rule set(CRS)/ Admin protection / Known bad inputs / SQL database / PHP application などがあり、CRS は「Web アプリに一般的に適用でき、OWASP Top 10 など OWASP 刊行物に記載の高リスク・多発脆弱性を含む広範な脆弱性の悪用から保護する」と明記されています(出典: https://docs.aws.amazon.com/waf/latest/developerguide/aws-managed-rule-groups-list.html)。
セキュリティグループより一段深く「中身」を見ますが、見ているのはあくまで既知の「パターン」です。
境界は「形」と「パターン」まで ── 認可はまだ誰も見ていない
ここまでを1行にまとめます。
- セキュリティグループは L3/4 の「形」(IP・ポート)を見る。
- WAF は L7 の既知「パターン」を見る。
どちらも「このリクエストは正当な形か」までしか見ていません。「この人がこのデータを見てよいか」という認可の判断は、まだどこでもされていないのです。
この差が、冒頭の現象の正体です。では実際に、境界に2種類のリクエストを投げてみましょう。
【実演】同じWAFが、SQLiは弾いてIDORは素通しする
ここが本記事の山場です。以下は example.com を使った説明用のフィクスチャで、値そのものは架空です。ただし構図は本物で、第1回で見た billpay.com/api/v1/cust/459(CCT 教材由来)と同じものを、境界の視点から見直します。
デモの前提 ── 宛先も認証も同じ、変えるのは中身だけ
条件をそろえます。宛先の WAF も、認証済みのセッションも固定です。変えるのは、投げるリクエストの中身だけです。
- (A) SQLi のペイロード
' or '1'='1(URL エンコードして混ぜる) - (B) IDOR、つまり認証済みのまま ID を
124に書き換えたGET /api/v1/cust/124
まず正常時の動きを押さえておきます。自分のデータは GET /api/v1/cust/123 で返ります。
$ curl -i "https://app.example.com/api/v1/cust/123"
HTTP/1.1 200 OK
Content-Type: application/json
{"id":123,"name":"山田太郎","email":"taro@example.com"} ← 自分のデータ
このあと、(A) は止まるのに (B) は通ってしまう、という対比に注目してください。
反例: SQLiペイロードはWAFが403でブロックする
まず (A)、SQLi のペイロードを送ります。
# 認証済みセッションで、顧客API(/cust/)の ID 位置に SQLi ペイロードを混ぜて送る(' or '1'='1 を URL エンコード)
$ curl -i "https://app.example.com/api/v1/cust/%27%20or%20%271%27%3D%271"
HTTP/1.1 403 Forbidden ← AWS WAF のマネージドルール(SQLi 検知)がブロック
Server: awselb/2.0
# ボディ: WAF によりリクエストが拒否された旨(AWS WAF の block アクション)
# → 境界(WAF)は「攻撃の"形"」を認識して止めた
返ってきたのは 403 Forbidden。WAF のマネージドルールが「攻撃の形」を認識してブロックしました。境界は確かに効いています。
ただし一点だけ注意します。これは SQLi 検知ルールを有効にした前提の一例で、設定やペイロード次第で弾かれないこともあります。「WAF は常に SQLi を弾く」と一般化はしないでください(その理由は後半の「なぜ素通しするのか」で扱います)。ここで見てほしいのは、攻撃の「形」をしたリクエストは境界で止まるという事実です。
山場: GET /api/v1/cust/124 は WAF も SG も素通しで 200
では (B)。同じ WAF、同じ認証済みセッションのまま、ID を 124 に書き換えただけの、ごく普通の GET です。
# 同じWAF・同じ認証済みセッションで、ID を 124 に書き換えただけの"正当な形"の GET
$ curl -i "https://app.example.com/api/v1/cust/124"
HTTP/1.1 200 OK ← WAF に一致する攻撃パターンなし・SG は 443 許可済み → 何も止めない
Content-Type: application/json
{"id":124,"name":"佐藤花子","email":"hanako@example.com"} ← 他人のデータが返る(=IDOR)
# → 境界は「文法的に正当な HTTP GET」を止める理由がない。認可はアプリ側の仕事
200 OK。返ってきたのは他人(佐藤花子さん)の氏名とメールアドレスです。WAF に一致する攻撃パターンはなく、セキュリティグループは 443(HTTPS)を許可済みなので、境界は何も止めませんでした。
同じ WAF です。SQLi は止めたのに、IDOR は通しました。これが本記事でいちばん見てほしい場面です。
いま起きたこと ── 境界は「攻撃の形」は弾くが認可は見ていない
いま起きたことを言葉にします。
- (A) SQLi →
403: 既知の攻撃パターンに一致したから弾いた。 - (B) IDOR →
200: 文法的に正当な HTTPGETだから通した。
境界は「形」で判断していて、中身が「誰のものか」は見ていません。CCT もファイアウォールの限界として「一般的なポートやアプリケーションから発生する攻撃を防御するものではない」と明記しています(出典: CCT eBook 書籍826-827/PDF837-838)。IDOR はまさに、一般的なポート(443)と正当なアプリケーション操作(GET)を悪用する攻撃です。
なお、こうやって ID を総当たりで試す挙動をログで検知して追跡する話は、第6回で扱います(近日公開予定)。次は、なぜ (B) が素通しするのかを構造で見ます。
なぜ素通しするのか ── 境界に「見えないもの」
さきほど体感した「なんとなく怖い」を、ここから「境界の構造的な限界」という言葉にきちんと翻訳していきます。
WAFは「攻撃パターン」を探す ── 正当なGETには一致しない
WAF は、シグネチャやルールで既知の攻撃(SQLi や XSS)を照合する道具です。図のように、/api/v1/cust/124 は文法的にまったく正当な HTTP リクエストで、どの攻撃パターンにも一致しません。
SQLi のほうは一致して 403 になりましたが、IDOR は不一致だから許可され、アプリへ素通りします。「正しく見える通信」を止める理由が、WAF には無いのです。マネージドルールは「既知」にしか反応しません。
セキュリティグループは「通信の形」しか見ない
ではセキュリティグループはどうか。すでに見たとおり、セキュリティグループは L3/4、IP・ポート・プロトコルだけを見ます。
Web サービスを公開する以上、443 番ポートは許可しないといけません。すると、その 443 の上を流れる「正当な形」の GET は、中身が何であってもセキュリティグループの関知外です。CCT もファイアウォールの限界として「パスワードの不正使用を防ぐものではない」「上位プロトコル層(アプリ層)からの攻撃をブロックしない」と明記しています(出典: CCT eBook 書籍826-827/PDF837-838)。セキュリティグループは通信の形しか見ていないので、中身の悪用は止められません。
CCTも明言 ── 限界を知らずに使うと「誤った安心感」を生む
ここが本記事の思想的な核です。CCT の教材には、こう書かれています。
ファイアウォールは、限界を理解せずに導入すると、誤った安心感を与えてしまうことがある。
そして限界の一つとして「プロトコルスタックの上位レベル(=アプリケーション層)からの攻撃をブロックしない」と明言しています(出典: CCT eBook 書籍826-827/PDF837-838)。
今回の IDOR や認可不備は、まさにこのアプリケーション層で起きる「正当な操作の悪用」です。攻撃の形をしておらず、正当な操作に見える。だから境界では止まりません。「境界を入れたから安全」という誤解を解く中心が、この一節です。境界は必須ですが、万能ではありません。
マネージドルールも万能でない ── 検査に上限、認可は対象外
「マネージドルールを全部有効にすれば防げるのでは?」と思うかもしれません。ここも過信は禁物で、理由は2つあります。
1つ目、WAF の検査には上限があります。AWS WAF のボディ検査サイズ上限は、2026年7月時点で次のとおりです(出典: https://docs.aws.amazon.com/waf/latest/developerguide/waf-oversize-request-components.html)。
- ボディ / JSON ボディ: Application Load Balancer と AppSync は先頭 8KB(固定・引き上げ不可)、CloudFront・API Gateway・Cognito・App Runner・Verified Access は既定 16KB(Web ACL 設定で最大 64KB まで引き上げ可)
- ヘッダ: 先頭 8KB かつ先頭 200個 まで
- クッキー: 先頭 8KB かつ先頭 200個 まで
そして重要なのは、AWS 公式が「AWS WAF がリクエストを許可して保護対象へ通すとき、検査できたサイズ・数の上限を超える内容も含め、リクエスト全体が送られる」と明記している点です。つまり上限を超えた部分は検査されずに素通りします。
2つ目、そもそも認可はルールの対象外です。何を書いても、WAF に「この人がこのデータを見てよいか」は判断できません。
だから WAF は「緩和(あるいは仮想パッチ)」であって、コードの根治の代替にはなりません。
だから「認可」は誰も見ていない
まとめます。セキュリティグループは形を見た、WAF はパターンを見た。でも「この人がこのデータを見てよいか」は、誰も見ていません。
リクエストはセキュリティグループを通り、WAF を通り、境界を全部通り抜けた先で、初めてアプリが認可を判断できます。OWASP の A01:2021 も、次のように述べています。
Access control is only effective in trusted server-side code or server-less API, where the attacker cannot modify the access control check or metadata.
(アクセス制御は、攻撃者が改変できない信頼されたサーバサイドのコード、あるいはサーバレス API でのみ有効である)
(出典: https://owasp.org/Top10/2021/A01_2021-Broken_Access_Control/)
だから認可はアプリで強制するしかありません。この線引きを、次章で設計の言葉に落とします。
どの脅威を、どの層で受けるか ── 線引きと多層防御
ここは羅列ではなく、1本の「線引き論」です。すべてが「認可はアプリ」に収束します。自社は Laravel の新規開発と FuelPHP のレガシー、両方を使っている前提で進めます。
線引きの原則 ── 境界は「形」を、アプリは「認可」を守る
核心の設計版はこれです。
- **境界(WAF / セキュリティグループ)**は、通信の形と既知パターンを守る。これは必須の第一層です。
- アプリは、誰が何を見てよいか、つまり認可を守る。これは境界の外側では代替できません。
大事なのは、両方が要るということです。境界だけでも守れませんし、アプリだけでも守れません。この2軸(境界 = 形、アプリ = 認可)が本記事の背骨です。
脅威 × 層マトリクス
第1回から第3回で扱った脅威を、どの層で受けるかに割り付け直したのが次の表です。これが設計判断の共有になります。
| 脅威 | WAF(L7) | セキュリティグループ / NACL(L3/4) | アプリ(コード) |
|---|---|---|---|
| SQLi | △ 緩和(既知パターンを弾く / 検査上限あり) | × | ◎ 根治(プレースホルダ = 第2回) |
| XSS | △ 緩和(既知パターンを弾く) | × | ◎ 根治(出力エスケープ = 第3回) |
| SSRF | △ 一部(メタデータ検知ルール等 / 上限あり) | × IMDS は止められない(egress は外部宛先の限定) | ◎ URL検証(第2回)+ IMDSv2(第2回) |
| IDOR / BOLA / 認可不備 | × 止まらない(文法的に正当) | × | ◎ 唯一の砦 = Object単位の明示的認可(第1回) |
「WAF で止まる / 止まらない」を列で明示しました。以下、行ごとに受け方を見ます。
SQLi / XSS ── WAFは緩和、根治はコード
SQLi と XSS は、WAF で既知パターンを弾いて攻撃を減らし、時間を稼げます。これは有用です。ただし、さきほど見たように検査には上限があり、許可時はリクエスト全体が転送されるので、完全ではありません。
だから根治はコード側です。SQLi はプレースホルダ(第2回)、XSS は出力エスケープ(第3回)。WAF は「緩和 / 仮想パッチ」、コードが「根治」。この二重で受けるのが原則です。
IDOR / BOLA / 認可不備 ── アプリの認可だけが唯一の砦
ここが本記事の主役です。IDOR・BOLA・認可不備は、アプリのみで受けます。
他人の ID に書き換えた 124 は、セキュリティグループを通過し、WAF も通過し、境界を全部通り抜けます。それでも、アプリにオブジェクト単位の明示的な認可があれば、最後の最後で 403 になります。
この「オブジェクト単位の明示的な認可」の具体的な実装(FuelPHP の所有チェック、Laravel の Gate / Policy による集約認可)は、第1回で詳しく扱いました。本記事ではその実装を再掲せず、「境界を素通りした 124 を止める最後の関門はここ」という結線だけしておきます(第1回)。
強調したいのは、「WAF があるから認可を省略」は最悪の設計だということです。境界は認可を代わりに守ってくれません。
SSRF ── egress とアプリ、IMDSはIMDSv2で
SSRF の受け方は、役割分離が要点です。
まず入口だけでなく出口(egress)を絞ります。セキュリティグループのアウトバウンドや VPC エンドポイントで、アプリが余計な外部宛先へ出ないよう限定します。加えてアプリの URL 検証(第2回)を組み合わせます。
ただし、ここで最も間違えやすい点があります。SSRF の狙い先であるインスタンスメタデータ(IMDS、169.254.169.254)について、AWS 公式は次のように明記しています。
- セキュリティグループは、EC2 インスタンスメタデータ宛/発のトラフィックをフィルタしない(出典: https://docs.aws.amazon.com/vpc/latest/userguide/vpc-security-groups.html)
- ネットワーク ACL は、IMDS へのトラフィックをブロックできない(出典: https://docs.aws.amazon.com/vpc/latest/userguide/vpc-network-acls.html)
つまり、IMDS はセキュリティグループや NACL の egress では止められません。SSRF → IMDS の第一防御は IMDSv2 + hop 制限(第2回で扱った内容)です。egress は「外部宛先の限定」には使えますが、「IMDS の遮断」には使えません。ここを混同しないでください。
セキュリティグループとNACLの使い分け(と共通の限界)
設計の勘所は1点です。セキュリティグループを基本の境界として ENI に付け、NACL はサブネット単位の粗い遮断に使う。機構の詳細な比較は次の表のとおりです(出典: セキュリティグループ・NACL の各公式ドキュメント)。
| 観点 | セキュリティグループ | ネットワーク ACL |
|---|---|---|
| 状態 | ステートフル(戻り自動許可) | ステートレス(戻りも明示) |
| 適用単位 | リソース(ENI) | サブネット |
| ルール | 許可のみ | 許可 + 拒否 |
| 評価 | 全ルール評価 | 番号順・最初の一致 |
| IMDS | 止められない | 止められない |
そして忘れてはいけないのが、どちらも IMDS は止められず、認可(中身)も見ていないことです。L3/4 をどう設計しても、「誰がこのデータを見てよいか」はセキュリティグループも NACL も見ていません。
WAFは運用で磨けるが、認可はルールの対象外
WAF は運用で磨く価値があります。ポイントは3点です(出典: AWS WAF 公式ドキュメント)。
- ルール: マネージドルールを本番前にテスト・チューニングする(AWS 自身が本番前のテストを推奨しています)
- レート: レートベースルールで、1分または5分あたりのリクエスト数が指定を超えたものをブロック / カウントする
- ログ: Web ACL のトラフィックログを CloudWatch Logs・S3・Amazon Data Firehose に出力する
これらは有用です。でも、どれだけ磨いても認可はルールの対象外です。「誰がこのデータを見てよいか」はルールに書けません。WAF の磨き込みは境界の仕事、アプリの認可は中身の仕事。別の仕事です(ログの活用・GuardDuty・VPC フローログは第6回で扱います)。
多層防御(defense in depth)── 1枚の壁に頼らない
ここで最初の層図に戻り、各層に対応する脅威を重ねます。
第1層の境界で SQLi や XSS を緩和し、第3層のアプリの認可で IDOR や BOLA を根治し、第4層の監視で素通りを検知する。これが**多層防御(defense in depth)**です。どれか1層が抜かれても、次の層で止めます。「WAF があるから安全」ではなく、「WAF も、セキュリティグループも、認可も、ログも」。全部が要る、というのが核心です。
レガシー / FuelPHPでも今日から
最後に、明日からの話です。「うちはレガシーの FuelPHP だから無理」で終わらせないでほしいのです。
- 「WAF / セキュリティグループがあるから認可は省略していい」という発想をやめる(最内層は必ずコードです)。
- FuelPHP やレガシーでも、所有チェック(第1回でやった認可の集約)は書けます。
- 境界の運用は運用チームの仕事、認可は開発の仕事。この両輪です。
冒頭で私が「境界を固めたからアプリは後回し」と思っていた、あの失敗への答えがこれです。
脅威 → 対策マッピング
さきほどの「脅威 × 層マトリクス」が WAF / SG・NACL / アプリの3層で受け止め方を細かく見た表なら、こちらは層の内訳を畳んで「境界(形)か、アプリ(認可・中身)か」の2軸に絞った、持ち帰り用の1枚です。
| 脅威 | 境界(形)での対策 | アプリ(認可・中身)での対策 |
|---|---|---|
| SQLi | WAF で緩和(既知パターン) | プレースホルダで根治(第2回) |
| XSS | WAF で緩和(既知パターン) | 出力エスケープで根治(第3回) |
| SSRF | egress で外部宛先を限定 | URL検証 + IMDSv2(第2回) |
| IDOR / BOLA | 止められない(文法的に正当) | Object単位の明示的認可(第1回) |
どの層で受けるかを決め、多層で守る。これが第1回から続く「脅威の地図」の、境界視点での姿です。
まとめ ── 「WAFがあるから安全」ではない
最後に、この記事の要点を振り返ります。冒頭に出した結論3点と、同じ言葉で締めます。
- 境界(WAF / セキュリティグループ)は通信の形 = IP・ポート・既知パターンを判断する。
- 中身の正当性(認可)は境界では判断できず、アプリでしか塞げない。
- 脅威ごとに受ける層を決め、多層で守る。
同じ WAF が SQLi は弾くのに IDOR は素通しした理由は、いまなら当然の帰結として見えるはずです。境界は「形」を見て「攻撃の形」を止めますが、GET /cust/124 のように文法的に正当な操作の悪用は、形をしていないので止まりません。「誰がこのデータを見てよいか」は、境界を全部通り抜けた先のアプリでしか判断できないのです。
ちょっと前の私がいちばん助かったであろう一言は、「境界は必須だが、認可の代わりにはならない」でした。ここが腑に落ちると、WAF の設定も、セキュリティグループのポートも、アプリの認可の1行も、すべて「どの脅威をどの層で受けるか」という一本の線でつながります。
Next action: 明日からできる3つ
理想論で終わらせないために、明日からできる具体を3つ挙げます。
- 棚卸し: WAF とセキュリティグループの Web ACL・ルール・ポートを棚卸しして、「何を止めて、何を通しているか」を書き出す。
- 認可確認: WAF 任せにしている画面や API に、アプリ側の認可(第1回)がちゃんとあるかを確認する。
- ログ有効化: WAF ログと VPC フローログの出力を有効化する(第6回、ログと追跡の準備になります)。
このうち1つでも赤信号があれば、そこが「境界任せ」の穴です。まずは棚卸しから始めてみてください。
あわせて読みたい
本シリーズは順次公開予定です。公開され次第、以下の「近日公開予定」を実 URL に差し替えます(未公開のうちはハードリンクしません)。
- 本シリーズ第1回: 「認証を通しても他人のデータは見える ── オブジェクト単位の認可を忘れると IDOR になる」。本記事の主役である「オブジェクト単位の明示的な認可」を具体コードで扱っています。境界を素通りした
124を最後に止める砦の実装です。 - 本シリーズ第2回: 「URL を入れたら AWS の鍵が漏れた ── 入力を実行に混ぜる SQLi と SSRF」。本記事のデモで使った SQLi ペイロード、および SSRF → IMDS の第一防御である IMDSv2 + hop 制限・URL 検証を扱っています。
- 本シリーズ第3回: 「コメント欄の
<script>でログイン状態を乗っ取られる ── XSS・CSRF・セッション管理の急所」。マトリクスで挙げた XSS の根治(出力エスケープ)を扱っています。 - 本シリーズ第4回: 「MD5で保存したパスワードは一瞬で平文に戻る ── 暗号・シークレット管理の急所」。境界・WAF の外にある暗号の中身(パスワードのハッシュ・シークレット管理)を扱っています。
- **第6回(セキュアログ・インシデント追跡)**では、境界を素通りした攻撃を WAF ログ・VPC フローログ・GuardDuty でどう追うかを扱う予定です(近日公開予定)。
参考
- AWS WAF(概要・関連付け先・アクション): https://docs.aws.amazon.com/waf/latest/developerguide/what-is-aws-waf.html
- AWS WAF Managed Rules(マネージドルールグループ一覧): https://docs.aws.amazon.com/waf/latest/developerguide/aws-managed-rule-groups-list.html
- AWS WAF Baseline rule groups(Core rule set / OWASP Top 10 対象): https://docs.aws.amazon.com/waf/latest/developerguide/aws-managed-rule-groups-baseline.html
- AWS WAF 検査サイズ上限(オーバーサイズ処理。2026年7月時点の現行値): https://docs.aws.amazon.com/waf/latest/developerguide/waf-oversize-request-components.html
- AWS WAF ログ出力(CloudWatch Logs / S3 / Data Firehose): https://docs.aws.amazon.com/waf/latest/developerguide/logging.html
- Amazon VPC セキュリティグループ(ステートフル / ENI 単位 / IMDS をフィルタしない): https://docs.aws.amazon.com/vpc/latest/userguide/vpc-security-groups.html
- Amazon VPC ネットワーク ACL(ステートレス / サブネット単位 / IMDS をブロックできない): https://docs.aws.amazon.com/vpc/latest/userguide/vpc-network-acls.html
- OWASP Top 10 ── A01:2021 Broken Access Control(認可はサーバサイドコードでのみ有効 / IDOR を例示): https://owasp.org/Top10/2021/A01_2021-Broken_Access_Control/
- CCT 日本語 eBook ── Module 07(Network Security Controls – Technical Controls。ファイアウォールの機能・種類・限界: 書籍791・806-811・825-827 / PDF802・817-822・836-838)