はじめに
「CloudFront を前に置いてキャッシュを効かせているから、ブルートフォースにも DDoS にも強い」。設計レビューの場で、こういう発言を一度は聞いたことがないだろうか。あるいは、自分でもなんとなくそう思っていたかもしれない。なお、ここで言う CloudFront は AWS の CDN(エッジ配信)、DDoS は Distributed Denial of Service(分散型サービス妨害)のことだ。
結論から言うと、これは誤解だ。キャッシュは性能の道具であって、攻撃を防ぐための道具ではない。特にブルートフォースにはほぼ効かないし、DDoS でも「たまたま効く場面がある」程度の補助でしかない。攻撃対策をキャッシュ任せにすると、守れているつもりで穴が空く。そして攻撃者は、その穴をピンポイントで突いてくる。
この記事を貫くテーマは、次の 2 つだ。
- キャッシュ誤解:キャッシュは防御の本体ではない。ブルートフォースには効かず、DDoS でも副次的(キャッシュ可能な GET を吸収するだけ)。
- 層で道具を選ぶ:攻撃の層(L3/L4=ネットワーク/トランスポート層 vs L7=アプリケーション層、総当たり vs 流量)で道具が決まる。Shield → WAF(Web Application Firewall)→ スロットリング → アプリ層で多層に守る。
「ブルートフォースと DDoS の違い → キャッシュの守備範囲 → それぞれの正しい防ぎ方」の順に、AWS のどのサービスをどの層に効かせるのかを地図にしていく。読み終わるころには、自分の構成図を見て「どの層が手薄か」を指させるようになっているはずだ。
1. まず分ける ― ブルートフォースと DDoS は別物
両者はよく同じ「攻撃対策」の箱に放り込まれるが、狙いも、効く層も、防ぐ道具もまったく違う。混同すると、道具を選び間違える。
家にたとえると分かりやすい。ブルートフォースは「玄関の鍵を片っ端から試して中に入ろうとする」攻撃だ。狙いは侵入=機密性の突破で、当たり(正しいパスワード)を 1 つ見つければ成功する。一方の DDoS は「玄関前を大勢で埋めて、住人すら入れなくする」攻撃だ。狙いはサービスを落とすこと=可用性の枯渇で、そもそも中に入る気はない。
ブルートフォースにも種類がある
ひとくちに総当たりと言っても、実務で見るのは次のような変種だ。
- 純粋な総当たり / 辞書攻撃:1 アカウントに対して、ありがちなパスワードや辞書の単語を次々試す。
-
パスワードスプレー:逆に「
Password123!のような定番パスワード 1 つ」を、大量のアカウントに対して薄く広く試す。1 アカウントあたりの失敗回数が少ないので、素朴なロックアウトをすり抜ける。 - クレデンシャルスタッフィング:どこかで漏れた「ID とパスワードのリスト」をそのまま使い回す。人はパスワードを使い回すので、これが一番厄介で、しかも成功率が高い。
ポイントは、**新しいものほど「分散」していて「1 つ 1 つは正常に見える」**こと。後の対策の話で「IP 単位のレート制限だけでは足りない」と言うのは、これが理由だ。
DDoS にも層がある
DDoS も層で分かれる。
- L3/L4(ネットワーク/トランスポート層):SYN フラッド(TCP の接続要求だけを大量に送りつける)が代表例だ。あるいは UDP リフレクション/アンプリフィケーション(DNS・NTP などの応答が大きいプロトコルを踏み台にして、増幅した帯域を浴びせる)もある。いずれも 帯域とコネクションを枯渇させるタイプだ。
- L7(アプリケーション層):HTTP フラッド(普通の GET/POST を大量に投げる)や Slowloris(接続をだらだら保持してワーカーを占有する)が代表例だ。アプリの処理能力を枯渇させるタイプで、一見正常なリクエストなので見分けが難しい。
整理すると、こうなる。
| 観点 | ブルートフォース | DDoS |
|---|---|---|
| 狙い | 認証突破(機密性) | 可用性の枯渇(落とす) |
| 成功条件 | 1 つ当てれば勝ち | 処理しきれず詰まれば勝ち |
| 量 | 少量〜中量で執拗(分散型もある) | とにかく大量 |
| 効く層 | L7(HTTP のログイン等) | L3/L4(SYN/UDP フラッド)・L7(HTTP フラッド) |
| 主な防御 | レート制限・ロックアウト・MFA(多要素認証) | Shield・エッジ分散・WAF |
L3/L4 はネットワーク/トランスポート層(IP・TCP/UDP のレベル)、L7 はアプリケーション層(HTTP のレベル)を指す。「どの層で殴られているか」で打ち返す道具が変わる、というのがこの記事の背骨だ。
2. キャッシュは何をして、何をしないのか
ここで本題のキャッシュだ。CloudFront のキャッシュも API Gateway(API の受け口を担う AWS のマネージドサービス)のステージキャッシュも、本来の仕事はオリジンの負荷とレイテンシを減らすことにある。同じ内容を何度も要求されたとき、オリジンに毎回作らせず、エッジ(利用者に近い拠点)に置いた完成品を返す。いわば「よく出る注文を作り置きしておく」仕組みだ。
そもそも「何がキャッシュされる」のか
CloudFront は、リクエストからキャッシュキーを作り、それが一致したら作り置きを返す。キャッシュキーには既定でメソッド・ホスト・パスが入る。クエリ文字列・ヘッダ・Cookie を含めるかどうかは、キャッシュポリシー次第だ。そして重要なのは次の 2 点だ。
-
GET/HEADが基本。POST/PUT/DELETEのような書き込み系は、原則キャッシュされない(してはいけない)。 - レスポンスの
Cache-Control(no-store/private/max-ageなど)と CloudFront 側の TTL(Time To Live、エッジに保存しておく期間)で、保存するか・どれだけ保存するかが決まる。
「どれだけヒットしているか」は キャッシュヒット率というメトリクスで見える。静的サイトならここを 90% 以上に持っていける一方、動的 API は構造的にヒット率が上がらない。
ブルートフォースにキャッシュは効かない
ログイン試行は ID とパスワードが毎回違うので、リクエストの中身(多くは POST のボディ)が毎回変わる=作り置きが使えない。そもそも認証系のレスポンスは Cache-Control: no-store でキャッシュ禁止にするのが鉄則だ。成功結果をキャッシュしたら、別人に他人のセッションを返すという致命的な事故になるからだ。だから認証リクエストはキャッシュ層を素通りしてオリジンに届く。総当たりに対してキャッシュは原理的に無力だ。
DDoS には「条件付きで」効く
攻撃が「キャッシュ可能な静的 GET」への洪水なら、エッジでヒットしてオリジンに到達しないので、結果的に吸収できる。静的 LP のような構成では、これは本物のメリットだ。エッジで跳ね返している間、オリジンは平穏でいられる。
ただし、本気の攻撃者はわざとキャッシュを外してくる。
- クエリ文字列を毎回ランダムに変える(
?x=8f3a1、?x=2b9c7…)=キャッシュバスティング -
POSTを投げる、ログインや検索のような動的エンドポイントを狙う - キャッシュしない設定のパスを集中的に叩く
こうなるとリクエストはオリジンに直撃し、キャッシュは何もしてくれない。むしろ「キャッシュがあるから安心」と油断していると、動的経路だけを狙われてあっさり落ちる。
つまりキャッシュは、「キャッシュできるものへの大量アクセスを、たまたま吸収できる」だけ。防御の主役に据えるものではない、というのが誤解の核心だ。性能のために入れる。防御は別で用意する。これを分けて考える。
3. ブルートフォースの正しい防ぎ方
総当たりを止める発想はシンプルで、「試行回数を絞る」に尽きる。鍵を無限に試せるから破られるのであって、回数を制限すれば現実的な時間では破れなくなる。AWS なら次の層を重ねる。
① AWS WAF レートベースルール
同一 IP(や指定したキー)からの直近 5 分間のリクエスト数がしきい値を超えたら、自動でブロックする。CloudFront・ALB・API Gateway(REST API)などにアタッチできる、総当たりの「執拗さ」をそのまま止める一枚目だ。実務で効かせるコツがいくつかある。
-
集約キーを選ぶ:素の送信元 IP だけでなく、
X-Forwarded-Forのヘッダ、あるいは複数キーの組み合わせで数えられる。プロキシ配下では集約キーを間違えると全員一括ブロックになるので注意。 -
適用範囲を絞る(scope-down statement):全パスではなく
/loginや/api/tokenだけにレート制限をかける。静的配信まで巻き込まないために重要。 - まず Count モードで観測する:いきなり Block にせず、しきい値で何件引っかかるかをログで見てから Block に切り替える。NAT 配下の正規ユーザーを巻き込む誤検知を避けられる。
② API Gateway スロットリング / 使用量プラン
API Gateway には流量制御が組み込まれている。
-
既定のスロットリング:リージョン・アカウント単位で「毎秒 10,000 リクエスト・バースト 5,000」といった既定値がある(引き上げ申請も可)。トークンバケット方式(一定速度で補充される処理枠を消費していく方式)で、超えた分は自動で
429 Too Many Requestsを返す。 - ステージ/メソッド単位:「このログイン API だけ毎秒 5 リクエストまで」のように、エンドポイント単位で細かく絞れる。
- 使用量プラン + API キー:利用者ごとに「1 日 1 万回まで」のような上限をかけられる。外部公開 API で効く。
クライアント側は 429 を受けたら指数バックオフ(待ち時間を倍々に延ばして再試行)するのが作法。攻撃者はこれを無視して叩き続けるが、そのぶん WAF のレートルールに引っかかる、という二段構えになる。
③ アプリ層のロックアウトとバックオフ ― ただし罠がある
「n 回失敗したらアカウントを一時ロック」は定番だが、ロックアウト自体が攻撃の道具になることを知っておきたい。攻撃者がわざと他人のアカウントで失敗を繰り返せば、正規ユーザーをロックして締め出せる(これも一種の DoS だ)。
だから現実解は、永久ロックではなく「一時ロック+指数バックオフ+本人通知」。失敗のたびに待ち時間を延ばし、一定時間で自動解除し、不審なら本人にメールで知らせる。これで「破られにくさ」と「正規ユーザーの締め出し」のバランスを取る。
④ MFA と CAPTCHA ― 分散型への最終回答
第 1 章で触れたパスワードスプレーやクレデンシャルスタッフィングは、1 IP あたりの試行が少ないので IP 単位レート制限をすり抜ける。ここは別の道具が要る。
- MFA(多要素認証):パスワードを当てられても、second factor がなければ突破されない。最も効果的な一手。
- WAF Bot Control / CAPTCHA・Challenge アクション:自動化されたボットを見分け、人間チェックを挟む。
- Account Takeover Prevention(ATP)マネージドルール:漏洩済み資格情報の使い回しなど、乗っ取り特有のパターンを検知する WAF のマネージドルールグループ。クレデンシャルスタッフィング対策に向く。
余談だが、姉妹記事の「Basic 認証」で挙げた弱点 ―― 仕様自体にレート制限の概念がない ―― は、まさにこの章の話につながる。Basic 認証単体は総当たりを止められないので、その前段に WAF やスロットリングを置いて回数を絞る、というのが現実解になる。
4. DDoS の正しい防ぎ方
DDoS は 1 つの道具で防ぐものではなく、層ごとに受け止める。AWS の場合、実はかなりの部分が最初から守られている。
① Shield Standard ― 無料で常時オン
すべての AWS ユーザーに自動・無料で付いている。CloudFront・Route 53・Global Accelerator のエッジで特に強力だ。L3/L4 の一般的な DDoS(SYN フラッド、UDP リフレクション等)をインラインで吸収してくれる。「何もしなくてもここは守られている」と知っておくだけで、設計の安心感が違う。逆に言うと、エッジサービスを通さず生のサーバーを晒すと、この恩恵を取りこぼす。
② CloudFront のエッジ分散
CloudFront は世界中のエッジロケーションでトラフィックを受けるので、攻撃が 1 か所に集中しない。Anycast(同じ IP アドレスを各地のエッジに応答させる仕組み)で最寄りのエッジに分散され、volumetric(大量帯域)型を面で受け止める土台になる。前章のキャッシュも、ここでは「ヒットする分はオリジンに流さない」という形で副次的に効く。
③ AWS WAF(L7)
HTTP フラッドのようなアプリ層 DDoS には、WAF で対抗する。
- レートベースルール:第 3 章と同じ仕組みで、過剰なリクエスト元を絞る。
- 地理ブロック(geo match):サービス対象外の国からの大量アクセスを丸ごと落とす。
-
マネージドルール:
Common Rule SetやKnown Bad Inputsなど、既知の悪性パターンを AWS 側がメンテしてくれるルール群。最初に入れておくと土台ができる。
④ Shield Advanced(有料)― どこで踏み切るか
月額 $3,000+データ転送料・1 年契約の上位オプション。次の価値で踏み切りを判断する。
- 大規模・高度な攻撃への強化された緩和
- 24/7 の専門チーム SRT(Shield Response Team)支援:攻撃中に相談できる
- コスト保護:DDoS でオートスケールした分の課金を補償してくれる(攻撃で請求が青天井になる恐怖への保険)
- ヘルスベース検知、可視化ダッシュボード、対象は CloudFront / Route 53 / Global Accelerator / ALB / EIP
「落ちたら売上・信用に直結する」「攻撃での課金増が怖い」本番系で効いてくる。逆に個人開発や検証段階では、無料の Standard + WAF で十分なことが多い。
⑤ いちばん見落とす ― オリジンを隠す
ここが本当に重要だ。前段にどれだけ Shield や WAF を積んでも、オリジンの素の URL や IP を直接叩かれたら全部素通りされる。攻撃者はまず「CloudFront を迂回して生のサーバーを直接殴れないか」を探す。だから、
- **S3 オリジンは OAC(Origin Access Control)**で、CloudFront 経由以外の直アクセスを遮断する。
-
ALB/EC2 オリジンは、CloudFront 経由のみ許可する。具体的には、セキュリティグループで AWS の CloudFront 用マネージドプレフィックスリスト(
com.amazonaws.global.cloudfront.origin-facing)だけを通す方法がある。あるいは、CloudFront が付与する秘密のカスタムヘッダを ALB 側で検証する方法でもよい。 - オリジンの直 IP / 直 DNS を公開しない。DNS 履歴や証明書から足がつくこともあるので、設計時から「表に出るのは CloudFront だけ」にする。
よくある落とし穴
最後に、現場で繰り返し見る取りこぼしを 3 つ。
- WAF をリージョナル(ALB)にだけ付けて、エッジ(CloudFront)前段が無防備。L7 攻撃はエッジで止めたい。
- レートのしきい値が緩すぎて意味がない/厳しすぎて正規ユーザーを巻き込む。Count モードで実測してから決める。
- 「キャッシュがあるから DDoS は平気」と思い込み、動的 API の経路を素のまま晒す。
まとめ ― 層 × 攻撃 × AWS の道具
最後に、この記事の地図を 1 枚の表にしておく。
| 層 | 主な攻撃 | AWS の道具 |
|---|---|---|
| L3/L4(ネットワーク) | SYN/UDP フラッド、リフレクション | Shield Standard(自動・無料)/ Shield Advanced |
| エッジ | volumetric な大量アクセス | CloudFront(分散・キャッシュ)/ Route 53 |
| L7(HTTP) | HTTP フラッド、Slowloris | AWS WAF(レートベース・マネージドルール・geo) |
| 認証 | ブルートフォース、スプレー、スタッフィング | WAF レート + APIGW スロットリング + ロックアウト + MFA / ATP |
| オリジン | 直叩きで前段を迂回 | OAC / セキュリティグループ / カスタムヘッダで秘匿 |
おわりに
キャッシュは性能の道具であって、防御の本体ではない。攻撃対策は「キャッシュを入れたか」ではなく、「どの層が守れているか」で考える。これが伝えたかったことのすべてだ。
最後に、二本柱をもう一度。
- キャッシュ誤解:ブルートフォースにキャッシュは効かない。DDoS でも「キャッシュ可能なものを吸収する補助」にとどまる。
- 層で道具を選ぶ:L3/L4 は Shield、L7 は WAF と CloudFront、総当たりはスロットリングとロックアウトと MFA。攻撃の層に合わせて道具を当てる。
次の一歩として、自分の構成図を 1 枚出してみてほしい。そして、こう問う。
- L3/L4 は Shield に守られているか?
- L7 にレート制限(WAF / スロットリング)はあるか?
- 認証にロックアウトと MFA はあるか?
- オリジンへの直アクセスは塞いだか?
このうち 1 つでも「ノー」があれば、そこがキャッシュでは埋まらない穴だ。埋めるべきは、その穴である。