こんにちは。セキュリティの世界へようこそ。
現場でバリバリとコードを書いていると、「とりあえず動くものを作る」ことに必死で、セキュリティの細かなルールは後回しになりがちですよね。でも、その「後回し」が、ある日突然、サービスを根底から揺るがす大惨事に繋がることがあります。
今回は、数ある攻撃手法の中でも、特に「一度火がつくと被害が止まらない」厄介な「格納型XSS(Stored XSS)」について、泥臭い現場の知見を交えながら、家を守る防犯の視点でお話しします。
—
格納型XSSとは?——「家の壁に毒を塗られる」恐怖
Webサイトの掲示板やプロフィール欄。これらは、ユーザーが書いたものを保存し、他の人に見せる場所ですよね。
格納型XSSは、「悪意のあるスクリプトを、サービス運営者のデータベースという『家の中』にこっそり忍び込ませる」攻撃です。
泥棒に例えると…
反射型XSSが「通りすがりの通行人に罠を仕掛ける」行為だとすれば、格納型XSSは「家の表札に、触れると麻痺する毒を塗っておく」ようなものです。
一度壁に毒(スクリプト)を塗ってしまえば、その家を訪れた人、通りかかった人、全員がもれなく毒に触れてしまいます。しかも、その毒は時間が経っても消えず、次の訪問者を待ち続けます。データベースに一度保存されてしまうと、そのデータが表示されるたびに、被害が無限に再生産される……これが格納型XSSの恐ろしさです。
—
なぜ「サニタイズ」が必要なのか?
データベースに保存する際、なぜ「サニタイズ(無害化)」が必要なのでしょうか。それは、「ブラウザは、渡されたものが『文字』なのか『命令』なのかを区別できないから」です。
例えば、ユーザーが以下のようなコメントを入力したとします。
ブラウザはこの文字を見ると、「おっ、これは実行すべきプログラムだな!」と判断し、何も疑わずに実行してしまいます。結果、あなたのサイトを利用しているユーザーのブラウザから、大切な「クッキー(ログイン情報)」が攻撃者のサーバーへ送信されてしまうのです。
—
現場で実践する「鉄壁」の守り方
「サニタイズ」という言葉を聞くと難しく感じるかもしれませんが、要は「ブラウザが『命令』と勘違いしないように、文字を安全な形に変換する」だけのことです。
1. 入力時ではなく「出力時」に変換する
よくある間違いが、「データベースに入れるときに変換する」ことですが、これはおすすめしません。データが変換されてしまうと、検索機能などで不具合が起きたり、あとで別の場所で使いたいときに困るからです。
鉄則:保存はそのまま(必要ならバリデーションのみ)、表示する瞬間に変換する。
2. 具体的なコード例(PHPの場合)
PHPでWebサイトを作っているなら、htmlspecialchars関数が頼れる相棒です。
// ユーザーが入力したコメントを表示する際
// ENT_QUOTES: シングルクォーテーションも安全に変換する
// ‘UTF-8’: 文字化けを防ぐお約束
echo htmlspecialchars($user_comment, ENT_QUOTES, ‘UTF-8’);
こうすると、という文字は、ブラウザにとって無害な「ただの記号の羅列」に変換されるため、攻撃が発動しなくなります。
---
防御の最後の砦:セキュリティヘッダー
コードの修正に加えて、ブラウザ自身にも「もし変なスクリプトが混ざっていても、勝手に実行しないでね」と命令を出しておきましょう。これが「CSP(Content Security Policy)」です。
Webサーバーの設定で、以下のようなヘッダーを追加するだけで、防御力は格段に上がります。
HTTPレスポンスヘッダーの設定例
「信頼できる場所からのスクリプトしか実行しない」というルール
Content-Security-Policy: default-src 'self'; script-src 'self';
この設定を入れておくと、仮に攻撃者が悪意あるスクリプトを埋め込んだとしても、ブラウザが「あ、このスクリプトは外部の怪しい場所から来たものだ! 実行しちゃダメだ!」とブロックしてくれます。
---
まとめ:一歩ずつ、確実に。
セキュリティは、「完璧な魔法」を探すことではありません。「自分たちの家(アプリケーション)に、どんな入り口があって、どこから泥棒が入りそうか」を想像し、一つひとつ鍵をかけていく作業です。
1. 出力時は必ずエスケープ(htmlspecialcharsなど)する。
2. CSPヘッダーでブラウザにガードを固めてもらう。
まずはこの2つから始めてみてください。これだけでも、Webサイトの安全性は劇的に向上します。
セキュリティは、開発者がユーザーを守るための「優しさ」です。これからも、安全で楽しいWebサービスを一緒に作っていきましょう!何かあれば、いつでも相談してくださいね。
コメント