---
title: あなたが知らなそうなAWS WAFの話
tags: 
author: [raiha](https://image.docswell.com/user/raiha)
site: [Docswell](https://www.docswell.com/)
thumbnail: https://bcdn.docswell.com/page/3EK9NN4LED.jpg?width=480
description: JAWS-UG彩の国埼玉支部 #8 彩の国埼玉支部 1周年 https://jawsug-sainokuni-saitama.connpass.com/event/387763/
published: May 31, 26
canonical: https://image.docswell.com/s/raiha/Z7NJDN-things-you-dont-know-about-aws-waf
---
# Page. 1

![Page Image](https://bcdn.docswell.com/page/3EK9NN4LED.jpg)

あなたが知らなそうな
AWS WAFの話
2026/5/30
JAWS-UG
#8
raiha(Ryo Aihara) / @raiha_tec
彩の国埼玉支部 彩の国埼玉支部 1周年


# Page. 2

![Page Image](https://bcdn.docswell.com/page/L73WVVL675.jpg)

aws sts get-caller-identity
仕事
SOC運用やログ分析基盤を作ってます
趣味
(最近やってないけど)自作スピーカー / 自作キーボード
AI/ローカルLLMで遊ぶ
自作Aqua Voice
Google MeetでVTuberするChrome拡張(右下)
𝕏: @raiha_tec
LT
彩の国埼玉支部 2回目(#0、今回)
Slidevでの発表 2回目
Security-JAWS CfP落ちの内容を話します
好きなAWSサービス
ECS / CDK
埼玉歴30数年
かわいい


# Page. 3

![Page Image](https://bcdn.docswell.com/page/87DK88NMJG.jpg)

本日の立ち位置
👶
初心者
▶
📰
電通総研ブログ
▶
🧑‍💻
中級者
┊
横道
▶
🧙
上級者
🌳
今日の話
📰 電通総研ブログ（前提）
「AWS WAF について最初から知りたかったこと8選」
= 初心者:Lv200と中級者:Lv300の間ぐらい？
8 KB / マネージドルールのバージョン / etc.
📖 電通総研ブログ：AWS WAF について最初から知りたかったこと8選
🌳 今日の話（このLT）
どちらかといえば中級者だが、なくても困らない…か？
明日からすぐ使える！系の話はないです


# Page. 4

![Page Image](https://bcdn.docswell.com/page/VJPK885QE8.jpg)

①もはや知られていないことで有名な8KB
「
※ AWS WAF
Body
の例
について最初から知りたかったこと8選」にも記載あり
0KB
8KB
16KB
...
50KB
│
│
│
│
████████ ← ここまでしか見ない (8 KB まで)
────────┃ &gt; 8,192 B で Block ※Count に下げると無効
████████████████████████████████████████
└─ padding ─┘└── &#039; OR 1=1 -- ──────────┘
(ダミー)
(8 KB 以降の死角に隠す)
WAF 本体検査(ALB)
CRS Block 閾値
攻撃者の細工
→ SQLi / XSS のマネージドルールも 8 KB 以降は見ない。攻撃部分が完全に WAF の死角に入る
📏 WAF 仕様上限（Body）
：
固定（拡張不可）
CloudFront / APIGW 等：16 KB → 最大 64 KB へ拡張可
Body部のうち、先頭8~64KBまでをAWS WAFは検査する
ALB / AppSync 8 KB
📖 AWS Docs: Oversize request components in AWS WAF
⚠️ CommonRuleSetの誤った理解
は &gt; 8,192 B で Block
→ 単に大きいリクエストを拒否するルールと考えると…
→ Count にすると「8KB以降のBody部が検査されない」
= 攻撃されやすい・気づきづらい
`SizeRestrictions_BODY`


# Page. 5

![Page Image](https://bcdn.docswell.com/page/2EVVNNPPEQ.jpg)

①続 サイズは書けるが、個数は書けない
`Cookie:`
🍪 1 🍪 2 🍪 3 … 🍪 200 ┃ 💣 201 💣 202 …
👁️ WAF が見る範囲（先頭 200 個）
✅ サイズはカスタムで書ける
SizeConstraintStatement:
FieldToMatch:
Body: { OversizeHandling: MATCH }
ComparisonOperator: GT
Size: 16384
# ← 16 KB 超を Block
🙈 見えない領域（201 個目以降）
❌ 個数で書く手段がない
やりたいこと
Cookie
可否
が 201 個以上 で Block
❌
が 201 個以上 で Block
❌
Header
💡 `SizeConstraintStatement` は Content-Length ベースなの
で
WAF 側に「先頭 200 個まで」の 検査上限 があるのに、
検査範囲(8KB)を超えるサイズでも書ける
statement に 「個数を数える」プリミティブが無い
→ CRS の `SizeRestrictions_BODY` (8KB) より大きい閾値も自
→ 検査上限を超えた死角を、個数で塞げない
由に設定可
🚨 小さな Cookie を 200 個以上詰めれば、201 個目以降にペイロードを隠せる


# Page. 6

![Page Image](https://bcdn.docswell.com/page/57GLKKPQEL.jpg)

🧪 FieldToMatch × OversizeHandling
CloudFront + WAF
で「Header 値に `BLOCKME` を含めば Block」のルールを構成。ダミー Header の数と marker 位置を変えて curl で検証
検査方式
OversizeHandling
（名前指定）
が範囲内
≤ 個目)
marker
( 200
が範囲外
≥ 個目)
marker
201
marker
( 201
＋
無し
個超
(n/a)
🛑 Block
🛑 Block
✅ Allow
any
🛑 Block
🛑 Block
✅ Allow
`Headers` + `All`
`CONTINUE` (既定)
🛑 Block
✅ Bypass
✅ Allow
`Headers` + `All`
`NO_MATCH`
🛑 Block
✅ Bypass
✅ Allow
`Headers` + `All`
`MATCH`
🛑 Block
🛑 Block
🛑 誤検知 Block
`SingleHeader`
`Headers` + `IncludedHeaders`
🔑 名前指定（SingleHeader / IncludedHeaders）は 200 個制限の対象外 — 名前で直接取り出すため位置と無関係
🔑 全件スキャン（Headers / All）のみ 200 個制限が効く — 既定の `CONTINUE` は バイパス余地アリ、 `MATCH` はバイパス潰せるが正
規 200 個超ユーザを誤検知


# Page. 7

![Page Image](https://bcdn.docswell.com/page/4EQYNN2WJP.jpg)

🛠️ ② boto3 で WAF 更新時の LockToken
WAF
は 楽観ロックでリソース管理。 `LockToken` を握っていないと更新が拒否される
❌ LockTokenなし
✅ `get` で取得 `update` に渡す
import boto3
c = boto3.client(&#039;wafv2&#039;)
# 1. get で LockToken を取得
r = c.get_web_acl(Name=&#039;my-acl&#039;,
Scope=&#039;REGIONAL&#039;, Id=&#039;abc123&#039;)
lt = r[&#039;LockToken&#039;] # ← これ
c.update_web_acl(
Name=&#039;my-acl&#039;, Scope=&#039;REGIONAL&#039;,
Id=&#039;abc123&#039;,
DefaultAction={&#039;Allow&#039;: {}},
Rules=[...], VisibilityConfig={...},
)
#
WAFOptimisticLockException
💥
# 2. update に LockToken 同梱
c.update_web_acl(
Name=&#039;my-acl&#039;, Scope=&#039;REGIONAL&#039;, Id=&#039;abc123&#039;,
DefaultAction={&#039;Allow&#039;: {}},
Rules=r[&#039;WebACL&#039;][&#039;Rules&#039;],
VisibilityConfig=r[&#039;WebACL&#039;][&#039;VisibilityConfig&#039;],
LockToken=lt, # ← 必須
)
🔑 Web ACL / Rule Group / IP Set / Regex Pattern Set すべて LockToken 必須。 `WAFOptimisticLockException` を食らったら再 `get` してリトライ


# Page. 8

![Page Image](https://bcdn.docswell.com/page/KJ4WGGL171.jpg)

📐 WCU: WebACL Capacity Unit
雑に言うと ルールの大きさ 。ルールが複雑だと必要なWCUは大きくなる。
🧱 3階層の WCU 上限
Web ACL
💡 知らないとハマるポイント
─┬─ 基本料金で 1,500 WCU
├─ 最大
5,000 WCU
└─ 超過分は 追加課金
Rule Group ┬─ 最大
5,000 WCU
└─ 作成時に Capacity 確定
(immutable / 変更不可)
Rule ─────┬─ タイプ毎に WCU が違う
├─ SizeConstraint → 低
└─ Regex / JsonBody → 高
の はimmutable
→ 中の ルール追加 / 削除 / 更新は自由
→ ただし合計 WCU は宣言値内に収める必要あり
→ 超過する場合は Rule Group ごと作り直し
Rule Grop WCU
🔒
に載せた Rule Group のコストは
実 WCU ではなく宣言した Capacity 値で固定
→ 固定されているので、Rule Group内を自由に更新しても、Web ACLにル
ールを載せられる。
Web ACL
transformation / JSON body inspection
🔑 WCU は「実際の検査内容には影響しない、AWS 側のリソース予約」。だから事前計画が大事
を足すとルール WCU が 増加


# Page. 9

![Page Image](https://bcdn.docswell.com/page/LE1YDDL57G.jpg)

🛠️ ③ `check_capacity` で WCUの計算
デプロイする前にWCUの試算ができる
引数のルールを 構文 validation という効果も
✅ `check_capacity` の使い方
💡 構文 validation も同時に走る
import boto3
c = boto3.client(&#039;wafv2&#039;)
resp = c.check_capacity(
Scope=&#039;REGIONAL&#039;, # or CLOUDFRONT
Rules=[{&#039;Name&#039;: &#039;block-bad-bots&#039;,
&#039;Priority&#039;: 1,
&#039;Action&#039;: {&#039;Block&#039;: {}},
&#039;Statement&#039;: {...},
&#039;VisibilityConfig&#039;: {...}}])
print(resp[&#039;Capacity&#039;]) # → 5 WCU
引数の `Rules` をパースするので、不正なルールがあると
`WAFInvalidParameterException` を返してくる
検出される構文エラー（例）：
ネスト不可な statement のネスト
`OR Statement` にネスト1個だけ
不正な `FieldToMatch` / パラメータ値
→ Dry-run として CI に仕込めば WCU 超過 + 構文ミスを同時検査（IPSet ARN
実在性などは別 API）
🔑 マネージドルールは `describe_managed_rule_group` で個別 WCU を取得 → `check_capacity` に渡して合算試算もできる


# Page. 10

![Page Image](https://bcdn.docswell.com/page/GEWGYYVWJ2.jpg)

🎲 例題：このルール、何 WCU？
rule1 — JP × `.*/test/.*`
rule2 — US × `.*/example/.*`
{
{
}
&quot;Statement&quot;: { &quot;AndStatement&quot;: { &quot;Statements&quot;: [
{ &quot;GeoMatchStatement&quot;: {
&quot;CountryCodes&quot;: [&quot;JP&quot;] } },
{ &quot;RegexMatchStatement&quot;: {
&quot;RegexString&quot;: &quot;.*/test/.*&quot;,
&quot;FieldToMatch&quot;: { &quot;Body&quot;: {...} },
&quot;TextTransformations&quot;: [
{ &quot;Priority&quot;: 0, &quot;Type&quot;: &quot;URL_DECODE&quot; },
{ &quot;Priority&quot;: 1, &quot;Type&quot;: &quot;LOWERCASE&quot; }
] } }
] } }
}
&quot;Statement&quot;: { &quot;AndStatement&quot;: { &quot;Statements&quot;: [
{ &quot;GeoMatchStatement&quot;: {
&quot;CountryCodes&quot;: [&quot;US&quot;] } },
{ &quot;RegexMatchStatement&quot;: {
&quot;RegexString&quot;: &quot;.*/example/.*&quot;,
&quot;FieldToMatch&quot;: { &quot;Body&quot;: {...} },
&quot;TextTransformations&quot;: [
{ &quot;Priority&quot;: 0, &quot;Type&quot;: &quot;URL_DECODE&quot; },
{ &quot;Priority&quot;: 1, &quot;Type&quot;: &quot;LOWERCASE&quot; }
] } }
] } }
🤔 両方を同じ Web ACLに載せたとき、消費 WCU は何？
単純合計と `check_capacity` の結果は一致する？


# Page. 11

![Page Image](https://bcdn.docswell.com/page/47ZLXX42J3.jpg)

🎲 例題：まずは 1 ルールの WCU
📖 公式表のWCUを使って rule1 / rule2 の WCU を積み上げてみる
構成要素
公式表の WCU
内訳
`GeoMatchStatement` ( `JP` or `US` )
1
1 WCU
`RegexMatchStatement` (Body)
3
3 WCU
`URL_DECODE` transformation
+10
10 WCU
`LOWERCASE` transformation
+10
10 WCU
集約)
`AndStatement` (
子の合計
—
= 24 WCU
→ rule1 = 24 WCU / rule2 = 24 WCU …なので 2 ルールの合計は？


# Page. 12

![Page Image](https://bcdn.docswell.com/page/YJ6W44G6JV.jpg)

🎲 例題：答え合わせ
✨ `check_capacity` で実測すると… 💡 なぜ 20 WCU 減るのか
c.check_capacity(
Scope=&#039;REGIONAL&#039;,
Rules=[rule1, rule2]
)
# → {&#039;Capacity&#039;: 28}
単純合計
実測値
差分
48 WCU ████████████████
28 WCU █████████
-20 WCU ← 最適化分
両ルールが同じ条件を満たしている：
同じ component（Body）を検査
同じ transformation（URL_DECODE + LOWERCASE）を適用
→ AWS WAF は 変換処理を 1 回にまとめる
→ 2 ルール分の transformation コスト
`(10 + 10) × 2 = 40` のうち 半分の 20 WCU が削減
🔑 同じ component に同じ transformation を当てるルールが増えても WCU はリニアに増えない。Web ACL 内 / Rule Group 内のどちらでも最適化される


# Page. 13

![Page Image](https://bcdn.docswell.com/page/GJ5MQQV5J4.jpg)

🎲 最適化が効く / 効かないパターン
同じ rule1 / rule2 でも 配置の仕方 で最適化の効き方が変わる
✅ パターン A
Web ACL
に直接 2 ルール
┌─ Web ACL ─────────┐
│ rule1
│
│ rule2
│
└───────────────────┘
→ 28 WCU ✨
（最適化が効く）
✅ パターン B
❌ パターン C
つの Rule Group
別々の Rule Group
┌─ Web ACL ─────────┐
│ ┌─ RuleGroup ───┐ │
│ │ rule1
│ │
│ │ rule2
│ │
│ └───────────────┘ │
└───────────────────┘
┌─ Web ACL ─────────┐
│ ┌─ RG-A ────┐
│
│ │ rule1
│
│
│ └───────────┘
│
│ ┌─ RG-B ────┐
│
│ │ rule2
│
│
│ └───────────┘
│
1
観点
RG
WCU
内（実消費）
Web ACL
視点
└───────────────────┘
28
✨
観点
RG
の 宣言 Capacity 値
RG-A / RG-B
→ RG 内では最適化が効く（実 WCU が下がる）
WCU
内
Web ACL
点
視
24 / 24
各 RG の 宣言 Capacity 値の
合計


# Page. 14

![Page Image](https://bcdn.docswell.com/page/9E29PP3G7R.jpg)

🛠️ ④ 今ブロック中の IP を覗く
`get_rate_based_statement_managed_keys`
件）
📋 何が取れるか
リスト（現在
にハマってる ）
IPv4 / IPv6
rate limit
IP
最大 10,000 件。超過分はレート最大のものが残る
Web ACL × Rule Group × Rate-based rule 単位で独立管理
⚠️ 制約
が `IP` or `FORWARDED_IP` の rule のみ
`CONSTANT` / `CUSTOM_KEYS` だと
`WAFUnsupportedAggregateKeyTypeException` 💥
→ Cookie ベース等の rate-limit は不可視
`AggregateKeyType`
で 現在 rate-limit にハマっている IP を取得（最大 10,000
🔧 使い方
import boto3
c = boto3.client(&#039;wafv2&#039;)
resp = c.get_rate_based_statement_managed_keys(
Scope=&#039;REGIONAL&#039;,
WebACLName=&#039;my-acl&#039;,
WebACLId=&#039;abc123&#039;,
RuleName=&#039;block-too-many-reqs&#039;,
)
print(resp[&#039;ManagedKeysIPV4&#039;][&#039;Addresses&#039;])
# → [&#039;203.0.113.5&#039;, &#039;198.51.100.42&#039;, ...]
print(resp[&#039;ManagedKeysIPV6&#039;][&#039;Addresses&#039;])
🔑 障害時の「今、誰が引っかかってる？」をログ無しで即時取得可。CloudWatch メトリクスでは IP 単位まで見えない


# Page. 15

![Page Image](https://bcdn.docswell.com/page/D7Y4551GEM.jpg)

まとめ
の死角 — サイズは弾けるが、個数は弾けない
2. LockToken — boto3 で更新するなら `get` → `update`
3. `check_capacity` — WCUの試算API
4. WCU の話 - テキスト変換のWCU
5. `get_rate_based_statement_managed_keys` — 今ブロック中の IP
1. 8 KB
知らないよりは知っていたほうがいいはず…
📝 話さなかったこと：WAF ログフォーマットの話 — 細かい話で長くなるのでカット


# Page. 16

![Page Image](https://bcdn.docswell.com/page/VENYNN28J8.jpg)

📢 告知 ① — JAWS SONIC 2026
JAWS SONIC 2026 / MIDNIGHT JAWS 2026 - THE MARATHON -
土
〜 9/6 (日) 12:00 ／ オンライン開催 🌐
時間ぶっ通しの JAWS-UG オンラインイベント
2026/9/5 ( ) 12:00
24
🔗 jaws-ug.connpass.com/event/393837/


# Page. 17

![Page Image](https://bcdn.docswell.com/page/Y79PRR1XE3.jpg)

📢 告知 ② — JAWS FESTA AKITA 2026
JAWS FESTA AKITA 2026
土 ／ あきた芸術劇場ミルハス 🎭
秋田さ来てたんせ！ 🌾
2026/11/7 ( )
🔗 jawsfesta2026.jaws-ug.jp


# Page. 18

![Page Image](https://bcdn.docswell.com/page/G78DWW497D.jpg)

ご清聴ありがとうございました 🙏
💬 質問・感想はお気軽にどうぞ！
raiha
𝕏: @raiha_tec


