蓄積型XSSの「真の恐怖」:DBはすでに汚染されているかもしれない
やあ。今日も本番環境のログとにらめっこしている君へ。
セキュリティの教科書には「入力値をサニタイズせよ」と書いてあるが、現場で本当に恐ろしいのは、その「サニタイズ」という言葉の解釈を誤った結果、データベースそのものが攻撃の踏み台にされることだ。
特に「蓄積型XSS(Stored XSS)」は、一度DBに侵入を許すと、その後の復旧がいかに困難か。今回は、単なるアラート表示で終わらない、DB汚染という名の「時限爆弾」について話そう。
—
1. 蓄積型XSSのメカニズム:なぜ「保存」がゴールなのか
反射型XSSはURLを送りつける必要があるが、蓄積型は違う。攻撃者が掲示板やプロフィール欄に悪意あるスクリプトを書き込み、DBに保存させた瞬間、「そのページを見るユーザー全員」が攻撃対象になる。
攻撃者の視点:セッションハイジャックの自動化
攻撃者は、ただスクリプトを埋め込むだけじゃない。以下のような処理を仕込む。
// 攻撃者が掲示板に投稿した悪意あるスクリプト例
これがDBに入ると、管理者や一般ユーザーがそのページを開くたびに、ブラウザが勝手に裏でCookieを送信し始める。「入力時」の防御が甘いだけで、システム全体が恒久的な情報漏洩状態に陥るんだ。
—
2. 現場で使える防御戦略:「出口」で防ぐか、「入口」で叩くか
よくある間違いは、「表示時にエスケープすればいい」という甘い考えだ。それは正しいが、足りない。DB自体を汚染させないために、多層防御を徹底しよう。
実装例:Python (Flask/Jinja2) での堅牢な設計
現代のフレームワークは優秀だが、開発者が「|safe フィルタ」や「markup()」といった禁断の果実を使うと一発で終わる。基本はテンプレートエンジンの自動エスケープを信じろ。
from flask import Flask, request, render_template
import bleach # クリーニングライブラリ
app = Flask(__name__)
@app.route(‘/comment’, methods=[‘POST’])
def save_comment():
raw_input = request.form.get(‘comment’)
# 1. 入口での防御: HTMLタグをホワイトリスト形式で除去
# 許可するタグ以外は全て取り除く(
コメント