個人で運用していたタスク管理ツール(月間アクティブユーザー約300人)が、ある日突然攻撃を受けた。「こんな小さなサービス、誰が狙うんだ」と思っていた。結論から言えば、攻撃者は規模を選ばない。自動スキャンツールで脆弱なサーバーを片っ端から探しているだけだ。
異変の発見 ─ レスポンスタイムの異常
月曜の朝、ユーザーから「画面が重い」という問い合わせが2件入った。CloudWatch Metricsを確認すると、APIのp99レスポンスタイムが通常200msのところ4,800msまで悪化していた。CPU使用率は92%。t3.microの1台構成なので、アクセス増にはすぐ限界が来る。
最初は「バズったのか?」と思ったが、Google Analyticsのリアルタイムユーザーは普段通り8人。トラフィックの増加はユーザー起因ではなかった。
調査 ─ ログが語る攻撃の実態
ALBのアクセスログを確認した。
# 直近1時間のリクエスト数をIPごとに集計
zcat alb-access-log-*.gz | awk '{print $4}' | sort | uniq -c | sort -rn | head -20
結果、上位3つのIPから合計で秒間40リクエスト以上が来ていた。通常のユーザー行動では秒間0.5リクエスト程度なので、80倍の異常値だ。
リクエストの中身を見ると、SQLインジェクションの定番パターンがずらりと並んでいた。' OR 1=1 --、UNION SELECT、SLEEP(5) ─ 自動スキャンツールの典型的な挙動だ。
# SQLインジェクションパターンを含むリクエストを抽出
zcat alb-access-log-*.gz | grep -iE "(union|select|sleep|or\+1)" | wc -l
# 結果: 14,832件(直近6時間で)
対応 ─ 3時間の応急処置
ステップ1: 攻撃元IPの即時ブロック(所要10分)
# Security Groupで攻撃元IPをブロック
aws ec2 authorize-security-group-ingress \
--group-id sg-xxxxxxxx \
--protocol tcp --port 443 \
--cidr 0.0.0.0/0 # 既存ルール
# 攻撃元IPを拒否するNACLを作成
aws ec2 create-network-acl-entry \
--network-acl-id acl-xxxxxxxx \
--rule-number 50 \
--protocol tcp --port-range From=443,To=443 \
--cidr-block 203.0.113.0/24 \
--rule-action deny --ingress
ステップ2: WAFの導入(所要1時間)
それまでWAFを使っていなかった。「個人開発だしコストが…」と後回しにしていた。AWS WAFのマネージドルール(AWSManagedRulesCommonRuleSet)を適用し、SQLインジェクションとXSSの基本パターンをブロック。月額5ドル程度の追加コストで済んだ。
ステップ3: データベースの無事確認(所要30分)
最も恐れていたのはデータ漏洩だ。SQLインジェクションが成功していれば全ユーザーのデータが抜かれている可能性がある。
幸い、ORMを使っていたため直接的なSQL実行はされていなかった。スロークエリログを確認しても異常なクエリの実行履歴はなかった。ただし、これは運が良かっただけだ。
教訓 ─ 個人開発者が最低限やるべき5つのこと
教訓1: WAFは最初から入れる
AWS WAFのマネージドルールは月額数ドルで導入できる。「まだ小さいから」は理由にならない。攻撃者は規模を見ていない。
教訓2: レート制限を設定する
1つのIPからのリクエスト数に上限を設ける。ALBレベルでもアプリケーションレベルでもいい。秒間10リクエスト以上を許可する必要がある個人開発サービスはほぼない。
教訓3: ログは必ず保存する
攻撃に気づいた時、ログがなければ何が起きたのか分からない。ALBのアクセスログはS3への出力をONにしておく。デフォルトではOFFだ。
教訓4: 本番DBへの直接接続を禁止する
DBのセキュリティグループは、ALBやアプリケーションサーバーからの接続のみを許可する。自分のIPからの直接接続を開けっ放しにしている個人開発者は多い。
教訓5: アラートを設定する
CloudWatchでCPU使用率80%超過のアラートを設定する。今回、ユーザーからの問い合わせで気づいたが、アラートがあれば2時間早く対応できた。
aws cloudwatch put-metric-alarm \
--alarm-name "HighCPU" \
--metric-name CPUUtilization \
--namespace AWS/EC2 \
--statistic Average \
--period 300 \
--threshold 80 \
--comparison-operator GreaterThanThreshold \
--evaluation-periods 2 \
--alarm-actions "arn:aws:sns:ap-northeast-1:123456789:alerts"
まとめ
個人開発でも攻撃は来る。規模は関係ない。自動スキャンツールはインターネット上の全サーバーを無差別にスキャンしている。WAF、レート制限、ログ保存。この3つは個人開発でも初日から設定するべきだ。「うちは大丈夫」は、攻撃を受けるまで全員が思っていることだ。