現場のエンジニア諸君、今日も泥臭い戦いご苦労様。
セキュリティの教科書には「暗号化せよ」「入力をバリデーションせよ」としか書かれていないが、現実はそんなに甘くない。WAFのマネージドルールをONにした瞬間に正規のトラフィックまで遮断され、深夜の緊急会議で「とりあえずルールをオフにしてくれ」と叫んだ経験、一度はあるだろう。
今日は、暗号理論という「盾の基盤」を理解した上で、WAFという「最前線の防壁」をどう調整し、実務で使い倒すかについて、現場の知見を叩き込む。
—
1. 暗号の使い分け:原理を知らねば「鍵」は守れない
暗号化の基本だが、AES(共通鍵)とRSA/ECC(公開鍵)の使い分けを誤ると、インフラのパフォーマンスと強度は一瞬で崩壊する。
- AES(共通鍵暗号): 高速だが、鍵配送が地獄。通信の暗号化(TLSのペイロード部)や、DBの個人情報保管に使う。鍵管理にはAWS KMSなどのHSM(ハードウェアセキュリティモジュール)が必須だ。
- RSA/ECC(公開鍵暗号): 低速だが、安全な鍵共有ができる。TLSのハンドシェイクやデジタル署名に使う。最近はRSA 2048bitより、同等の強度で計算量が軽く、鍵長が短いECC(楕円曲線暗号)を選ぶのが定石だ。
現場の教訓: DBカラムの暗号化にRSAを使うな。AES-256-GCMを採用し、鍵のローテーション戦略を設計しろ。
—
2. WAFの「誤検知」を恐れるな、制御せよ
AWS WAFやGoogle Cloud Armorのマネージドルールは「魔法の杖」ではない。SQLインジェクションやXSSのパターンマッチングは、往々にして「特殊な入力」を攻撃と誤認する。
誤検知(False Positive)を封じ込める除外ルール
ルールを全部OFFにするのは論外だ。特定のURIパスやパラメータに対して、ルールを「カウントモード」にするか、除外設定を適用する。
例:特定の管理画面のみSQLiルールを緩める設定(JSON形式)
{
"Name": "Exclude-SQLi-for-Admin-Page",
"Statement": {
"AndStatement": {
"Statements": [
{ "LabelMatchStatement": { "Scope": "LABEL", "Key": "awswaf:managed:aws:sql-database:SQLi_QueryArguments" } },
{ "ByteMatchStatement": { "FieldToMatch": { "UriPath": {} }, "SearchString": "/admin/api/v1/query" } }
]
}
},
"Action": { "Allow": {} }
}
—
3. 実践:インジェクションを「無効化」する実装
WAFはあくまで「最後の砦」。アプリケーション側で脆弱性を潰していなければ、WAFの裏をかかれる。
SQLインジェクションを防ぐ(PHP / PDO)
「文字列連結」でSQLを作るのは、泥酔状態で地雷原を歩くのと同じだ。必ずプリペアドステートメントを使え。
// 悪い例: $sql = "SELECT * FROM users WHERE id = " . $_GET['id'];
// 良い例: プレースホルダーを使用する
$stmt = $pdo->prepare('SELECT * FROM users WHERE id = :id');
$stmt->execute(['id' => $_GET['id']]); // PDOが自動でエスケープ処理を行う
$user = $stmt->fetch();
XSSを防ぐ(JavaScript)
innerHTML は禁句だ。ブラウザが解釈する文字列の中にユーザー入力を混入させないことが鉄則。
// 悪い例: document.getElementById('output').innerHTML = userInput;
// 良い例: .textContent を使い、ブラウザに「文字列として」扱わせる
const userInput = new URLSearchParams(window.location.search).get('name');
const outputElement = document.getElementById('output');
if (userInput) {
// スクリプトタグが含まれていても、純粋なテキストとして描画される
outputElement.textContent = userInput;
}
—
4. 現場のプロが教える「インシデントハンドリングの極意」
WAFを調整する際、以下のステップを徹底してほしい。
1. ログを疑え: CloudWatch LogsやStackdriverで、ブロックされたリクエストをJSONで吐き出せ。「なぜブロックされたか」のラベル(SQLi_QueryArgumentsなど)を特定しろ。
2. 正規表現の闇: 複雑すぎる正規表現をWAFに書くな。それは攻撃者に「どこまでなら回避できるか」のヒントを与えることになる。
3. バリデーションは多層で:
- WAF層: 大まかな攻撃シグネチャを弾く。
- アプリ層: 型(数値のみ、メール形式など)を厳格にチェックする。
- DB層: 権限を最小限にし、不要な権限を与えない。
最後に:
セキュリティとは「100%防ぐ」ことではなく、「攻撃のコストを極限まで引き上げ、攻撃者に諦めさせる」ことだ。完璧な城壁を作ろうとして、出入口を塞いで運用を止めるな。設計の段階で脆弱性を排除し、WAFはあくまで「運用しながら叩く」ための補助輪として使いこなせ。
次回のログ解析で、お前たちがスマートに脆弱性を封じ込んでいることを期待している。健闘を祈る。
コメント