こんにちは。セキュリティの最前線で日々「泥棒」たちと知恵比べをしているエンジニアです。
今日は、Web開発の世界で最も有名で、かつ最も厄介な「クロスサイトスクリプティング(XSS)」について、少しだけお話ししましょう。堅苦しいマニュアルを読み込む前に、まずは「あなたの家」をイメージしてみてください。
そもそも、XSSって何が怖いの?
XSSを身近な例で説明すると、「信頼していたはずの玄関の鍵が、いつの間にか偽物にすり替えられている状態」です。
あなたが大切なお客さん(ユーザー)を家に招き入れるとき、玄関先で「いらっしゃいませ」と挨拶しますよね。でも、もし悪い泥棒が玄関の看板をすり替えて、偽の案内板を置いていたらどうでしょう?
お客さんはその案内板を信じて、大事な金庫の暗証番号を泥棒に教えてしまうかもしれません。
Webの世界では、この「案内板」がWebサイト上のテキストや画像です。攻撃者は、掲示板への書き込みやURLのパラメータなどを悪用して、「あなたのサイトの一部」に「悪意のある命令(スクリプト)」を紛れ込ませます。 これがXSSの正体です。
—
泥棒を締め出す「CSP(Content-Security-Policy)」という最強の門番
これまで、XSSを防ぐには「入力された文字をエスケープ(無害化)する」という対策が基本でした。でも、人間ですからミスはあります。そこで、「万が一、攻撃者が玄関に侵入しても、家の中で暴れさせない」ための強力な防波堤が、このCSP(コンテンツ・セキュリティ・ポリシー)です。
CSPは、Webサーバーからブラウザに対して、「このサイトでは、こういう場所からしかスクリプトを読み込んじゃダメだよ!」とルールを伝えるヘッダーのこと。これを設定すると、たとえ攻撃者が悪意あるコードを仕込んでも、ブラウザが「お前は許可されていないスクリプトだな。実行させないぞ!」と門前払いしてくれるようになります。
—
実践!「nonce」を使って信頼できるスクリプトだけを通す
CSPの中でも、最も推奨されるのが「nonce(ナンス)」を使った方法です。
「nonce」は、リクエストごとに生成される「使い捨ての合言葉」です。サーバー側でページを作るたびに、その時だけのランダムな文字列を発行し、許可するスクリプトにだけその合言葉を添えてあげます。
具体的な実装例
例えば、以下のようにヘッダーを設定します。
CSPヘッダーの設定例
‘strict-dynamic’ を使うと、許可されたスクリプトから読み込まれるものも自動で信頼されます
Content-Security-Policy: script-src ‘nonce-EDNnf03nceIOfn39fn3e’ ‘strict-dynamic’; object-src ‘none’; base-uri ‘none’;
そして、HTML側では以下のようにします。
この仕組みの素晴らしいところは、「書いた場所(HTMLファイルの中)」に直接埋め込まれたスクリプト(インラインスクリプト)をすべて禁止できるという点です。攻撃者がどこかに悪意あるコードを書き込んでも、そこに正しい「nonce」はついていないので、ブラウザは無視してくれるのです。
—
最後に:Reporting APIで「侵入の予兆」を知る
最後に、プロの現場で欠かせないのが「Reporting API」です。
CSPを設定すると、ルールに違反する試みがあった瞬間に、ブラウザがサーバーへ「今、誰かが変なスクリプトを実行しようとしましたよ!」と通知を送ってくれるようにできます。
違反レポートを特定のURLに送信する設定
Content-Security-Policy: …; report-uri /api/report-violation;
これにより、開発者は「自分のサイトが今、どこから狙われているのか」「どこに修正漏れがあるのか」をリアルタイムで把握できるんです。
—
一歩ずつ、強固な城を築こう
セキュリティは「完璧な防御」を目指すのではなく、「攻撃者が諦めるような仕組み」を多層的に積み上げることが重要です。
1. 基本: ユーザーの入力をそのまま表示せず、エスケープする。
2. 発展: CSPを導入して、不正なスクリプトが動かない土壌を作る。
3. 運用: Reporting APIで、常に異常を検知できる状態にしておく。
最初は難しく感じるかもしれませんが、この「鍵」を一つずつかけていく感覚さえ掴めれば、あなたの書くコードは格段に信頼性の高いものになります。一緒に、安全でワクワクするWebの世界を作っていきましょう!
何か分からないことがあれば、いつでも聞いてくださいね。応援しています。
コメント