そのスクリプト、本当に信頼できますか?CSPの「nonce」で守るWebサイトの防犯術
こんにちは!セキュリティの世界へようこそ。日々、Webサイトを作ったり運用したりしていると、「どうすれば攻撃を防げるのか?」と不安になることがありますよね。
今日は、Webサイトの「門番」として最強の威力を発揮するCSP(Content Security Policy)、その中でも特に強力な「nonce(ナンス)」という仕組みについてお話しします。
専門用語が並ぶと難しく感じるかもしれませんが、まずは「家の防犯」に例えて、一緒に紐解いていきましょう。
—
1. なぜ「外部のスクリプト」は泥棒になり得るのか?
Webサイトに表示されるスクリプト(JavaScript)は、サイトを便利に動かすための「お手伝いさん」です。しかし、攻撃者はこのお手伝いさんのふりをして、悪意のあるスクリプトを忍び込ませようとします。これが「クロスサイト・スクリプティング(XSS)」と呼ばれる攻撃です。
家の防犯で例えるなら、「誰が来ても『どうぞ』と家に入れてしまう」状態が、今の多くのWebサイトのセキュリティ状態です。
これに対抗するのがCSPです。CSPは「この家には、私が許可した人しか入れませんよ」という「招待状リスト」を玄関に貼るようなものですね。
—
2. ただの「招待状」では不十分な理由
CSPの基本的な設定では、「信頼できるドメイン(例:https://trusted.com)」を指定して、そこからの読み込みだけを許可します。
しかし、攻撃者は巧妙です。「信頼できるドメイン」の中にさえ、もし攻撃者がファイルを置けてしまったら?あるいは、サイトの中に最初からある「動的なスクリプト」が悪用されたら?
ここで登場するのが「nonce(ナンス)」です。
nonceって何?
nonceとは「Number used once(一度だけ使われる数字)」の略です。
これは、「その場限りの、使い捨ての合言葉」だと考えてください。
1. サーバーがページを表示するたびに、ランダムな合言葉(nonce)を生成します。
2. ページ内の「実行を許可するスクリプト」に、その合言葉を書き込みます。
3. 玄関の門番(ブラウザ)は、「合言葉が一致したスクリプト」だけを家の中に通します。
攻撃者がどれだけ怪しいスクリプトを差し込んでも、サーバーが発行した「今この瞬間の合言葉」を知ることはできないため、門番に追い返されるという仕組みです。
—
3. 実践:CSPポリシーを書いてみよう
では、実際にどのように設定するのか見てみましょう。HTTPレスポンスヘッダーに、以下のようなポリシーを設定します。
サーバーが送信するヘッダーの例
Content-Security-Policy: default-src ‘self’; script-src ‘nonce-EDNnf03nceIOfn39fn3e9h3sdf’;
そして、HTML側では以下のように記述します。
ポイント
- 毎回ランダムにする: 毎回同じ合言葉だと、攻撃者にバレてしまいます。リクエストごとに必ず新しい値を生成してください。
- 厳格に守る:
script-src 'unsafe-inline'のような設定は、合言葉(nonce)を無効化してしまうため、絶対に避けてくださいね。
—
4. 現場のプロからのアドバイス
実務で導入する際、最初から厳しく設定すると「あれも動かない、これも動かない」とサイトが真っ白になることがあります。まずは以下のステップで進めてみてください。
1. レポートモードを活用する: Content-Security-Policy-Report-Only というヘッダーを使えば、ブロックせずに「もしこれがCSPだったらブロックしていたよ」というログだけをサーバーに送信できます。
2. 少しずつ制限を強める: ログを見ながら、必要なスクリプトを一つずつ許可していくのが、現場で最も安全な進め方です。
3. 動的な生成を忘れずに: 昨今のフレームワーク(React, Vue, Next.jsなど)を使っている場合、サーバーサイドレンダリング(SSR)時にnonceを生成してHTMLに注入する仕組みを組み込むのが基本です。
—
最後に:セキュリティは「完璧」を目指さなくていい
セキュリティに「終わり」はありません。しかし、こうしてnonceのような仕組みを一つ取り入れるだけで、あなたのサイトの防御力は劇的に向上します。
「難しそう」と敬遠せず、まずは自分のサイトのヘッダーを確認するところから始めてみてください。一歩ずつ、泥棒が侵入できない強固なサイトを作っていきましょう!
もし実装で迷ったら、いつでもまた相談してくださいね。応援しています!
コメント