フリーキーズ | 独学プログラミング

Content Security Policyでスクリプト制限!初心者でもわかるCSP入門とXSS対策の基本

リンドくん

リンドくん

たなべ先生、Webサイトで「このスクリプトは実行できません」ってエラーが出たんですけど、これってなんですか?

たなべ

たなべ

それはおそらくContent Security Policy(CSP)が働いているね。
CSPは悪意のあるスクリプトからWebサイトを守るための重要なセキュリティ機能なんだよ。今日はその仕組みをしっかり学んでいこう!

Webサイトを作成していると、セキュリティという言葉を頻繁に耳にするのではないでしょうか。
その中でも特に重要なのがXSS(クロスサイトスクリプティング)攻撃への対策です。

Content Security Policy(CSP)は、このXSS攻撃を効果的に防ぐための強力なセキュリティ機構です。
この記事では、セキュリティ学習を始めたばかりの方でも理解できるよう、CSPの基本概念からスクリプト制限の実装方法まで、段階的にわかりやすく解説していきます。

プログラミング学習でお悩みの方へ

HackATAは、エンジニアを目指す方のためのプログラミング学習コーチングサービスです。 経験豊富な現役エンジニアがあなたの学習をサポートします。

✓ 質問し放題

✓ β版公開中(2025年内の特別割引)

HackATAの詳細を見る

Content Security Policyとは何か?

リンドくん

リンドくん

Content Security Policyって、具体的にどんな仕組みなんですか?

たなべ

たなべ

簡単に言うと、「どこから読み込まれたスクリプトなら実行していいか」をブラウザに指示する仕組みなんだ。
これによって、攻撃者が勝手に埋め込んだ悪意のあるスクリプトの実行を防げるんだよ。

CSPの基本概念

Content Security Policy(CSP)は、Webページ上で実行可能なリソースの読み込み元を制限するセキュリティ機構です。
HTTPヘッダまたはHTMLのmetaタグを通じてブラウザに指示を送ります。

CSPが解決する主な問題は以下の通りです。

  • XSS攻撃の防止 - 攻撃者が埋め込んだ不正なスクリプトの実行をブロック
  • データインジェクションの防止 - 想定外のリソース読み込みを制限
  • クリックジャッキングの軽減 - iframe埋め込みの制御

特筆すべきは、CSPがブラウザ側で動作する防御機構であるという点です。サーバー側だけでなく、クライアント側でも多層的な防御を実現できます。

なぜCSPが必要なのか

Webアプリケーションにおいて、ユーザー入力を適切にサニタイズ(無害化)することは基本中の基本です。しかし、人間が作るコードに完璧はありません。

例えば、以下のようなケースでXSS攻撃が成立してしまう可能性があります。

<!-- 危険な例:ユーザー入力をそのまま表示 -->
<div>
  ようこそ、<?php echo $_GET['name']; ?>さん!
</div>

攻撃者がnameパラメータに<script>alert('XSS')</script>を渡すと、そのスクリプトが実行されてしまいます。

CSPを導入すると、たとえこのようなコードの不備があったとしても、インラインスクリプトの実行自体をブラウザがブロックしてくれるのです。これは、セキュリティの「多層防御」の考え方に基づいた、非常に有効な対策と言えます。

CSPの動作の仕組み

CSPは、サーバーからブラウザへHTTPレスポンスヘッダとして送信されます。

Content-Security-Policy: script-src 'self' https://____.com

この指示を受け取ったブラウザは、以下のルールに従ってスクリプトの実行を制御します。

  1. 許可リスト方式 - 明示的に許可されたソースからのリソースのみ読み込む
  2. 違反の検出 - ポリシーに違反するリソース読み込みをブロック
  3. レポート送信 - 違反があった場合、指定されたエンドポイントにレポートを送信(オプション)

この仕組みにより、開発者が意図しないスクリプトの実行を効果的に防ぐことができます。

CSPでスクリプトを制限する基本設定

リンドくん

リンドくん

実際にCSPを設定するには、どうすればいいんですか?

たなべ

たなべ

設定方法は主に2つあるんだ。HTTPヘッダで設定する方法と、HTMLのmetaタグで設定する方法。
それぞれ見ていこうか。

HTTPヘッダでの設定

最も推奨される方法は、HTTPレスポンスヘッダでCSPを設定することです。

Apacheの場合(.htaccessまたはhttpd.conf)
Header set Content-Security-Policy "script-src 'self'"
Nginxの場合(nginx.conf)
add_header Content-Security-Policy "script-src 'self'";

Node.js(Express)の場合

app.use((req, res, next) => {
  res.setHeader(
    'Content-Security-Policy',
    "script-src 'self'"
  );
  next();
});

PHPの場合

header("Content-Security-Policy: script-src 'self'");

HTMLのmetaタグでの設定

HTTPヘッダが設定できない環境では、HTMLのmetaタグでも設定可能です。

<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Content-Security-Policy" content="script-src 'self'">
  <title>CSP Demo</title>
</head>
<body>
  <!-- コンテンツ -->
</body>
</html>

ただし、metaタグ方式には以下の制限があります。

  • frame-ancestorsディレクティブが使えない
  • report-uriディレクティブが使えない
  • サンドボックス機能が制限される

可能な限り、HTTPヘッダでの設定を推奨します。

script-srcディレクティブの基本

CSPの中でも、スクリプト制限に関わる最重要ディレクティブがscript-srcです。

基本的な指定方法

Content-Security-Policy: script-src <ソース指定>

よく使うソース指定

  • 'self' - 同じオリジン(ドメイン)からのスクリプトのみ許可
  • 'none' - すべてのスクリプトを禁止
  • https://____.com - 特定のドメインからのスクリプトを許可
  • 'unsafe-inline' - インラインスクリプトを許可(非推奨)
  • 'unsafe-eval' - eval()の使用を許可(非推奨)

実用的な設定例

Content-Security-Policy: script-src 'self' https://cdn.jsdelivr.net https://code.jquery.com

この設定では、以下のスクリプトが許可されます。

  • 同じドメインにあるスクリプトファイル
  • jsDelivrからのスクリプト
  • jQuery CDNからのスクリプト

逆に、以下のようなスクリプトはブロックされます。

<!-- ブロックされる:インラインスクリプト -->
<script>alert('Hello');</script>

<!-- ブロックされる:許可されていないドメイン -->
<script src="https://____.com/evil.js"></script>

<!-- ブロックされる:data URIスキーム -->
<script src="data:text/javascript,alert('XSS')"></script>

より安全なスクリプト制限の実装方法

リンドくん

リンドくん

'unsafe-inline'って使っちゃダメなんですか?便利そうなんですけど...

たなべ

たなべ

確かに便利だけど、これを許可するとXSS攻撃のリスクが大幅に上がるんだ。
代わりに、より安全なnonceやハッシュ方式を使うことを強く推奨するよ。

nonce方式による安全なインラインスクリプト

nonce(ナンス)は、一度だけ使用されるランダムな値で、特定のインラインスクリプトを安全に実行する仕組みです。

サーバー側でnonceを生成

<?php
// ランダムなnonceを生成
$nonce = base64_encode(random_bytes(16));

// CSPヘッダにnonceを含める
header("Content-Security-Policy: script-src 'self' 'nonce-{$nonce}'");
?>

HTML側でnonceを使用

<!DOCTYPE html>
<html>
<head>
  <title>Nonce Example</title>
</head>
<body>
  <!-- このスクリプトは実行される -->
  <script nonce="<?php echo $nonce; ?>">
    console.log('This script is allowed!');
  </script>
  
  <!-- nonce属性がないため、このスクリプトはブロックされる -->
  <script>
    console.log('This script is blocked!');
  </script>
</body>
</html>

nonce方式の重要なポイントは以下の通りです。

  • リクエストごとに異なる値を生成する必要がある
  • 攻撃者はnonce値を予測できないため、不正なスクリプトを実行できない
  • 'unsafe-inline'を使わずに必要なインラインスクリプトを実行できる

ハッシュ方式による安全なインラインスクリプト

ハッシュ方式は、スクリプトの内容のハッシュ値を事前に計算し、CSPに登録する方法です。

スクリプトのハッシュ値を計算

# SHA-256ハッシュの計算例
echo -n "console.log('Hello, World!');" | openssl dgst -sha256 -binary | openssl base64

出力例:

RFWPLDbv2BY+rCkDzsE+0fr8ylGr2R2faWMhq4lfEQc=

CSPヘッダにハッシュを設定

Content-Security-Policy: script-src 'self' 'sha256-RFWPLDbv2BY+rCkDzsE+0fr8ylGr2R2faWMhq4lfEQc='

HTMLでスクリプトを使用

<script>console.log('Hello, World!');</script>

このスクリプトは、内容が完全に一致するため実行が許可されます。

ハッシュ方式の特徴は以下の通りです。

  • スクリプトの内容が変わらない場合に有効
  • スクリプトが1文字でも変わるとハッシュ値が変わり、実行がブロックされる
  • 動的に生成されるスクリプトには不向き

strict-dynamic の活用

'strict-dynamic'は、CSP Level 3で導入された強力な機能です。

Content-Security-Policy: script-src 'nonce-abc123' 'strict-dynamic'

この設定により、以下のような挙動になります。

  • nonce付きスクリプトから動的に生成されたスクリプトも実行を許可
  • ホワイトリストに登録されたドメインは無視される
  • より柔軟で安全なスクリプト実行が可能

実用例

<script nonce="abc123">
  // このスクリプトは実行される
  const script = document.createElement('script');
  script.src = 'https://____.com/dynamic.js';
  document.body.appendChild(script);
  // 動的に追加されたスクリプトも'strict-dynamic'により実行される
</script>

よくある問題と解決策

問題① Google AnalyticsやGoogle Tag Managerが動かない

Content-Security-Policy: script-src 'self' https://www.googletagmanager.com https://www.google-analytics.com 'unsafe-inline'

理想的には、GTMをnonce方式で管理します。

問題② 外部CDNのライブラリが多すぎる

すべてのCDNをホワイトリストに追加するのではなく、以下を検討してください。

  • 可能な限りスクリプトを自サーバーにホスト
  • Subresource Integrity(SRI)を併用
  • 本当に必要なライブラリだけに絞る

問題③ 動的に生成されるスクリプトタグ

nonce方式またはstrict-dynamicの活用を検討してください。

// 動的スクリプトにnonceを付与
const script = document.createElement('script');
script.src = 'https://____.com/script.js';
script.nonce = document.querySelector('script[nonce]').nonce;
document.body.appendChild(script);

まとめ

リンドくん

リンドくん

CSPって思ったより奥が深いですね!でも、これでWebサイトのセキュリティがグッと上がりそうです。

たなべ

たなべ

その通り!CSPはXSS攻撃への強力な防御壁になるんだ。
最初は大変かもしれないけど、一度設定すれば長期的にサイトの安全性を高められるよ。ぜひ実践してみてね!

この記事では、Content Security Policy(CSP)によるスクリプト制限について、基本から実践的な導入方法まで解説してきました。

重要なポイントをおさらいしましょう。

  • CSPはXSS攻撃を防ぐ強力なセキュリティ機構 - ブラウザ側で不正なスクリプト実行をブロック
  • script-srcディレクティブで細かく制御 - 許可するスクリプトのソースを明示的に指定
  • 'unsafe-inline'は避ける - nonce方式やハッシュ方式で安全にインラインスクリプトを実行
  • Report-Onlyモードで段階的に導入 - 既存サイトへの影響を最小限に抑えながら導入可能

CSPはWebセキュリティにおいて多層防御の一翼を担う重要な技術です。
サーバー側でのサニタイズと組み合わせることで、より堅牢なWebアプリケーションを構築できます。

ぜひ、自分のプロジェクトでCSPを導入してみてください。最初は緩めのポリシーから始めて、徐々に厳格化していくアプローチがおすすめです。

この記事をシェア

関連するコンテンツ