【入門編】 Content-Security-Policy(CSP)によるXSSの多層防御 – オフェンシブセキュリティ & リバースエンジニアリング防御ガイド

こんにちは!Webアプリケーションの開発や、サイトの運営をしていると「セキュリティ」という言葉をよく耳にするようになりますよね。

特に、サイトの中に悪意のあるプログラムをこっそり仕込まれてしまう「XSS(クロスサイトスクリプティング)」という攻撃は、名前だけでも聞いたことがあるかもしれません。

「うちのサイトは入力チェックをしているから大丈夫!」と思っていても、サイバー攻撃者はあの手この手でその隙を突いてきます。そこで今回は、万が一サイトのどこかに穴が見つかってしまっても、被害を最小限に食い止めるための強力な盾、CSP(Content-Security-Policy)について、身近な防犯にたとえながら優しく紐解いていきたいと思います。

一歩ずつ、一緒にセキュリティの仕組みを学んでいきましょう!

—

1. 家の防犯で考える「XSS(クロスサイトスクリプティング)」の怖さ

まずは、XSSという攻撃が私たちのWebサイトでどういう状態を引き起こすのか、身近な「お家(マイホーム)」にたとえて考えてみましょう。

あなたが新築のマイホームを建てたとします。玄関には頑丈な鍵(入力値のバリデーションやサニタイジング)をかけ、泥棒が入ってこないように対策を万全にしました。これなら安心……だと思いますよね?

ところが、もし「家の郵便受け(掲示板やプロフィール入力欄など、ユーザーが自由に入れられる場所)」の構造にちょっとした欠陥があったらどうでしょう。
悪意を持った泥棒が、郵便受けから「偽物の合鍵」をそっと投げ入れ、家の中で自由に動き回れるような細工をしてしまったとします。

これがXSSの正体です。
Webサイトの表示する場所で、ユーザーが入力したデータをそのまま「お、これ文字だな!」と勘違いして実行してしまうと、ブラウザ(家の中)で泥棒のプログラム(scriptタグなど)が動き出してしまいます。その結果、ログイン中のユーザーの大切なCookie(お財布や身分証明書のようなもの)を盗まれてしまったり、勝手に別のページへ飛ばされたりしてしまうのです。

玄関の鍵(入力チェック)だけを頑丈にしていても、万が一そこを突破されたり、別の小さな隙間から侵入されたりしたとき……家の中を荒らし放題にされてしまいますよね。

—

2. 最強の防犯システム「CSP(Content-Security-Policy)」とは?

「じゃあ、玄関の鍵だけじゃなくて、家の中にも防犯カメラや赤外線センサー、あるいは『身元不明の人は一歩も通さない屈強な警備員』を置けばいいのでは?」

その発想こそが、今回ご紹介するCSP(Content-Security-Policy:コンテンツセキュリティポリシー)です。

CSPとは、Webブラウザに対して「このサイトでは、こういう場所から持ってきたプログラムしか動かしてダメですよ!」というお墨付きのルール(ルールブック)をあらかじめ教えてあげる仕組みのことです。HTTPレスポンスヘッダーという、ブラウザとサーバーがこっそりやり取りする伝言メモのような場所に設定します。

たとえば、CSPを使うと次のような強力なルールを作ることができます。

  • 「うちのサイトで動いていいプログラムは、うちのサーバーの中にあるファイルだけです!」
  • 「外部の怪しいサイトから持ってこられたプログラムは、絶対に実行しちゃダメです!」
  • 「画面の中に直接書き込まれた怪しいプログラム( <script>タグなど)も、無視しなさい!」

これさえ設定しておけば、たとえ悪意あるユーザーが郵便受けから偽のプログラムを投げ込んできたとしても、警備員(ブラウザ)が「おい、お前はルールブックに載っていない怪しい奴だな!動いちゃダメだ!」とその場でガッチリ押さえ込んでくれます。これが、CSPによる多層防御の姿です。

—

3. モダンの定番!「nonce(ノンス)」と「strict-dynamic」を使った安全な設定

「なるほど、外部のプログラムを禁止すればいいんだね!」と思った方、ちょっと待ってください。
現代のWebサイトでは、Googleアナリティクスのような外部ツールや、サイトを彩る便利なJavaScriptファイルをたくさん読み込んで動かしていることが多いですよね。

「全部一律で禁止」にしてしまうと、今度は動くはずの便利な機能まで動かなくなってしまいます。
そこで登場するのが、現代のモダンなCSP設定であるnonce(ノンス:その場限りの使い捨てパスワード)とstrict-dynamicという組み合わせです。

防犯にたとえるなら、「今日だけ有効な特別なパスワード付きの入場証」を配るようなものです。

実際のCSP設定のサンプルコード

実際のWebサーバーや、PHPなどのプログラム側では、次のようなHTTPヘッダーを設定してブラウザにルールを伝えます。

Content-Security-Policy: default-src 'self'; script-src 'nonce-abc123XYZ' 'strict-dynamic' https:; object-src 'none'; base-uri 'none';

この設定にどんな意味が込められているのか、一つずつ優しく見ていきましょう。

  • default-src 'self';
  • 基本的なルールとして、画像やスタイルシートなどは「自分自身のサーバー(self)」から読み込まれたものだけを許可します。
  • script-src 'nonce-abc123XYZ' 'strict-dynamic' https:;
  • ここが一番のキモです!
  • 'nonce-abc123XYZ':ページを読み込むたびにサーバー側でランダムに生成する「使い捨ての合言葉(ノンス)」です。この合言葉が貼ってあるプログラムだけは、実行が許可されます。
  • 'strict-dynamic':この合言葉を持った正当なプログラムが、さらに別のプログラムを読み込んで動かすことを許可します(最近の複雑なJavaScriptフレームワークに対応するためによく使われます)。
  • object-src 'none';
  • プラグイン(Flashなど、もう古いですが)を使った攻撃を防ぐため、オブジェクトの読み込みは一切禁止(none)にします。
  • base-uri 'none';
  • ページの基準URLを書き換えて、リンク先を勝手に別の詐欺サイトにすり替えられる攻撃を防ぎます。

—

4. 開発現場での実装イメージ(PHPのサンプル)

それでは、実際の開発現場でこの「使い捨ての合言葉(nonce)」をどのように組み込むのか、簡単なPHPのコードで見てみましょう。

<?php
// 1. ページを読み込むたびに、推測されにくいランダムな合言葉(nonce)を生成する
// bin2hex(random_bytes(16)) で安全でランダムな文字列を作っています
$nonce = bin2hex(random_bytes(16));

// 2. HTTPヘッダーにCSPを設定し、生成したnonceを組み込む
header("Content-Security-Policy: default-src 'self'; script-src 'nonce-" . $nonce . "' 'strict-dynamic' https:; object-src 'none';");
?>
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>CSPサンプルページ</title>
</head>
<body>
    <h1>ようこそ、セキュリティ学習ページへ!</h1>

    <!-- 3. 正常なJavaScriptを読み込むときは、必ず先ほど作った nonce を属性として付与する -->
    <script nonce="<?php echo htmlspecialchars($nonce, ENT_QUOTES, 'UTF-8'); ?>">
        // このコードは、nonceが一致するためブラウザで正常に実行されます!
        console.log("安全なスクリプトが実行されました。");
    </script>

    <!-- もしここで攻撃者が勝手に <script>alert('ハック!')</script> のようなコードを差し込んでも、
         nonce が付いていないため、ブラウザは実行を拒否して安全を守ってくれます! -->
</body>
</html>

このように、ページを表示するたびにサーバー側でランダムな合言葉を作り、それを正しいスクリプトのタグだけに持たせることで、攻撃者がこっそり仕込んだ偽のプログラムを完全にシャットアウトすることができるのです。

—

5. まとめと最初の一歩

今回は、XSSというおそろしい攻撃からWebサイトを守るための強力な盾、CSP(Content-Security-Policy)についてお話ししました。

  • 入力チェック(玄関の鍵)だけでは、万が一のときにすり抜けられるリスクがある。
  • CSP(防犯カメラや警備員のルール)を組み合わせることで、多層防御(何重もの守り)を作ることができる。
  • nonce や strict-dynamic を使えば、現代の複雑なWebアプリケーションでも安全性を高く保てる。

「セキュリティの設定って、なんだか難しそう……」と感じていた方も、こうして防犯にたとえて仕組みを知ると、少し身近に感じられたのではないでしょうか?

最初は、今のサイトにどんなCSPが効いているかをテストできる「レポート専用モード(Content-Security-Policy-Report-Only)」という優しい機能から試してみるのもおすすめです。
ぜひ、あなたの開発するWebサイトでも、今日から一歩ずつ、強力な防犯システムを取り入れてみてくださいね!

コメント

タイトルとURLをコピーしました