「静的サイトなら攻撃されにくいでしょ?」──そう思っていませんか?

実は公開直後から世界中のボットによるスキャンや攻撃リクエストが飛んできます。

この記事では、AWS上でS3CloudFrontを使った個人ブログ向けに:

  • WAFが防げる攻撃とその料金
  • 0〜数十円で実践できる無料対策
  • 具体的な設定手順(すぐ使えるコード付き)
  • WAFを導入すべきタイミング

を初心者向けにやさしくまとめました。

結論:手軽なのはWAF導入。無料枠を活用すればほぼ無料でも十分守れます。

1. WAFとは?─役割・防げる攻撃・料金

1-1. WAFの役割

WAF (Web Application Firewall)は、Webサーバーへ届くHTTPリクエストの中身を検査し、不正を門前払いする「荷物検査付きゲート」です。

AWS WAFをCloudFront前段に置くと、世界225以上のPoP(配信拠点)で即ブロックできます。

1-2. 防げる代表的な攻撃

  • EDoS(コスト増大攻撃)
  • インジェクション(SQLi/XSS)
  • SSRF(サーバーサイドリクエストフォージェリ)
  • ディレクトリトラバーサル
  • Hostヘッダー改ざん
  • ボット/スクレイピング
  • Slowloris(スローリクエスト)
  • 既知脆弱性エクスプロイト
  • ログイン総当たり(ブルートフォース)

1-3. WAFの料金

項目月額説明
Web ACL約¥750サイトごとに1つ
カスタムルール (×2)約¥3002本で十分
リクエスト検査 (100万回)約¥90アクセス数に比例
合計例約¥1,140月100万PVの場合
  • 月10万PV → 約¥230
  • 月30万PV → 約¥460
  • 月100万PV → 約¥1,140

2. WAFを使わず「ほぼ無料」で守る考え方

ポイントは 「動的コードを置かない」 + CloudFrontの無料機能 の活用です。

  • 静的サイトジェネレータでHTMLを生成、ユーザー入力フォームを置かない
  • S3バケットはパブリックアクセスブロック + CloudFront OACで非公開
  • CloudFrontでHTTPS強制・ヘッダー最小転送・アイドルタイムアウトを設定
  • robots.txtCloudFront Functionsで悪質UAをブロック

3. 攻撃別:無料でできる対策と手順

3.1 EDoS(コスト増大攻撃)

概要:攻撃者がCloudFrontやS3に大量リクエストを送りつけ、従量課金モデルの穴を突いて請求額を跳ね上げる手口です。単なるサービス停止(DoS)ではなく、運営を金銭的に追い詰める“Economic Denial of Sustainability”攻撃です。

対策:以下の二段構えで“金銭的防御”を実現します。

  • コスト監視:CloudWatch Billing Alarm/AWS Budgets で請求額を常時モニタリング
  • 自動カットオフ:しきい値超過通知 → SNS → Lambda 自動実行 → CloudFront 停止 & S3 ポリシー全拒否
  • 予防策:WAF のレートベースルールで異常大量アクセスを事前にブロック

手順:

  1. 請求メトリクスの有効化
    コンソール → Billing and Cost Management に移動 → 左メニューバーから請求設定 → アラーと設定を編集して「CloudWatch 請求アラートを受信する」
  2. Billing Alarm の作成
    CloudWatch → アラーム → アラームの作成 → メトリクスを選択 → Billing → 概算合計請求額でUSDを選択 → 静的しきい値を>にして50ドル程度を入力
  3. アクションの設定
    アラーム状態を選択 → 新しいトピックの作成から自分のメールアドレスを登録(メールで確認) → 一旦次へ → アラーム名を入力し作成
  4. Lambda 関数実装
    Lambdaをコンソールから起動 → 関数の作成 → 一から作成 → 関数名「CostCutoffFunction」 → コードソースに以下のコードを入力(DIST_IDとBUCKET_NAMEは自分のもの)
  5. // CloudFront 停止
              const cf = new AWS.CloudFront();
              const cfg = await cf.getDistributionConfig({Id:DIST_ID}).promise();
              await cf.updateDistribution({
                Id: DIST_ID,
                IfMatch: cfg.ETag,
                DistributionConfig: {...cfg.DistributionConfig, Enabled: false}
              }).promise();
              // S3 全拒否
              const s3 = new AWS.S3();
              await s3.putBucketPolicy({
                Bucket: BUCKET_NAME,
                Policy: JSON.stringify({
                  Version: "2012-10-17",
                  Statement:[{
                    Effect:"Deny",
                    Principal:"*",
                    Action:"s3:GetObject",
                    Resource:`arn:aws:s3:::${BUCKET_NAME}/*`
                  }]
                })
              }).promise();
  6. アラーム→Lambda連携
    作成したアラームの編集 → Lambdaアクションを指定し、アラーム発火時に自動実行。
  7. graph LR; A[Billing Alarmしきい値超過] -->|通知| B(SNSトピック); B -->|Lambda起動| C{自動アクション}; C -->|CloudFront停止| D[Distribution: Disabled]; C -->|S3アクセス拒否| E[BucketPolicy: Deny];
    コスト超過検知からCloudFront停止・S3アクセス拒否までの自動カットオフフロー

    3.2 インジェクション/XSS・SQL

    概要:ユーザー入力を通じて悪意あるスクリプト(XSS)やSQL文(SQLインジェクション)が実行され、情報漏洩や画面改ざんを招く攻撃です。

    対策:お問い合わせフォームや検索などの入力フォームを置かない。(もっとも簡単)

    手順:

    1. HugoやJekyllなどの静的サイトジェネレータのテンプレートで自動エスケープ(例:{{ .Content | htmlEscape }})をONにする。
    2. コメント欄やフォームなど、動的なユーザー入力機能を一切設置しない。
    3. CIツールでHTML構造のLintを導入し、<script>タグ混入などを検知する。

    3.3 SSRF(サーバーサイドリクエストフォージェリ)

    概要:サーバーが攻撃者指定の外部・内部ネットワークにリクエストを送らされ、バックエンド資源が悪用される攻撃です。

    対策:フロントエンドで呼び出すAPIを固定し、CORS設定で許可ドメインのみを許可します。

    手順:

    1. JavaScriptから呼び出すAPIエンドポイントを1つに絞り、パラメータを受け付けない固定URL設計にする。
    2. CloudFrontのレスポンスヘッダー設定で、Access-Control-Allow-Originを自ドメインのみに制限。
    3. 動的機能が必要な場合は、Lambda@Edgeなどを経由してドメインホワイトリストを強制する。

    3.4 ディレクトリトラバーサル

    概要:../」などで本来公開すべきでないファイルへアクセスし、機密情報を取得される攻撃です。

    対策:S3のキー正規化機能とバケットポリシーでListBucket権限を拒否します。

    手順:

    1. S3バケットのバケットポリシーで"Action": "s3:ListBucket"に設定。
    2. オブジェクトキーには必ず安全なプレフィックス(例:posts/)のみを使用。
    3. 「../」を含むリクエストはCloudFront Functionsでステータス403にリジェクトするコードを追加してもOK。

    3.5 Hostヘッダー改ざん

    概要:偽のHostヘッダーを使い、キャッシュポイズニングや不正リダイレクトを引き起こす攻撃です。

    対策:CloudFrontのCache Policyで転送するヘッダーを最小限に絞り、HTTPS強制でHost一致を担保します。

    手順:

    1. CloudFrontのキャッシュポリシーでHeader Forwardingを「Whitelist」に設定し、Host以外は転送しない。
    2. ACM証明書で独自ドメインを設定し、HTTP→HTTPSリダイレクトを強制。
    3. CloudFront FunctionsでHostヘッダー不一致時に403返却するロジックを追加するとさらに強固。

    3.6 ボット/スクレイピング

    概要:悪質なクローラーやスクレイパーが大量リクエストを送り、コンテンツ盗用や帯域・キャッシュ浪費を引き起こします。

    対策:robots.txtで一般クローラーを誘導し、CloudFront Functionsで悪質User-Agentをフィルタリング。

    手順:

    1. ドキュメントルートにrobots.txtを配置し、User-agent: *Disallow: /private/を設定。
    2. CloudFront Functionsを作成し、Viewer Requestイベントでevent.request.headers['user-agent']をチェック。
    3. 悪質と判断した場合は{ statusCode:403 }を返すロジックを実装し、Behaviorにアタッチ。
    sequenceDiagram; autonumber; BadBot->>CloudFront: GET /index.html User-Agent: BadBot; CloudFront->>Function: Viewer Request; Function-->>CloudFront: status 403; CloudFront-->>BadBot: 403 Forbidden;
    図2. 悪質UA(BadBot)をCloudFront Functionsで403ブロックするシーケンス

    3.7 Slowloris(スローリクエスト)

    概要:少量のリクエストを長時間にわたり維持し、同時接続数を枯渇させる攻撃です。

    対策:CloudFrontのデフォルトIdle Timeout(30秒)を利用して長時間接続を自動切断。

    手順:

    1. CloudFrontのViewer接続アイドルタイムアウトを標準30秒のまま運用。
    2. 必要に応じてオリジンのIdle Timeoutも短く調整。

    3.8 既知脆弱性エクスプロイト

    概要:Log4Shellなど公開済みの脆弱性を狙い、攻撃コードを実行する手法です。

    対策:サーバーサイドフレームワークを使わず、依存ライブラリはCIで常に最新化。

    手順:

    1. バックエンドを持たない静的サイト構成にする。
    2. ビルド環境で
      npm auditやDependabotを使い、脆弱性を自動修正。

    3.9 ログイン総当たり(ブルートフォース)

    概要:APIや管理画面への多数リクエストで認証を突破しようとする攻撃です。

    対策:管理画面はVPC内やVPN経由のみアクセス可とし、パブリックに公開しない。

    手順:

    1. AWS VPNまたはPrivate Hosted Zone経由で管理画面のEndpointを限定。
    2. パブリックDNSには管理Endpointを登録せず、外部から到達不可に設定。

3.10 攻撃別対策のまとめ

攻撃 無料対策 手順概要
EDoS(コスト増大攻撃) CloudWatch Billing Alarm+Lambdaで自動カット アラームを設定し、自動的にコストをカットするように
インジェクション/XSS ユーザー入力排除+自動エスケープ 静的サイト生成時にテンプレート自動エスケープON
SSRF API呼び出し先固定+CORS制限 JS固定URL + CloudFrontで許可ドメインのみ制御
ディレクトリトラバーサル ListBucket拒否 S3バケットポリシーでListBucketをDeny
Hostヘッダー改ざん ヘッダー最小転送+HTTPS強制 Cache PolicyでHostのみ許可
ボット/スクレイピング CloudFront FunctionsでUAフィルタ Viewer RequestにUAチェックFunctionを適用
Slowloris Idle Timeout自動切断 CloudFrontの30秒アイドルタイムアウトを利用
既知脆弱性エクスプロイト 静的構成+ライブラリ最新化 ビルド環境でnpm audit/Dependabotを導入
ブルートフォース 管理画面非公開 VPC/VPN内のみアクセス可に設定

4. すぐ使えるコード例(CloudFront Functions)

// blockBadBots.js
function handler(event) {
  var ua = event.request.headers['user-agent']?.value || '';
  if (ua.match(/curl|python|BadBot|crawler|scraper/i)) {
    return { statusCode: 403, statusDescription: 'Forbidden' };
  }
  return event.request;
}
  1. CloudFront → 関数 → 関数を作成 → 名前をblockBadBotsなどに
  2. コードを貼り付け、発行
  3. ディストリビューションのビヘイビアへ → 編集を押し、ビュワーリクエストに関数を選択

5. WAFを導入するタイミングの目安

  • 広告収益¥750〜1,500以上
  • コメント欄や検索などユーザー入力を追加したい
  • 企業案件でSLAを求められる

月約¥1,140のWAFは“安い保険”です。

6. まとめ

  • 静的ブログは0円でも多くの攻撃を防げる
  • 入力フォーム追加=リスク急増 → その時点でWAF導入を検討
  • CloudFront Functionsなど無料枠を駆使し、安全なサイト運営を楽しむ