セキュリティヘッダーとは
セキュリティヘッダーは、ブラウザに指示を与えてセキュリティを強化するHTTPレスポンスヘッダーです。
なぜ必要か
- 🔒 XSS攻撃の防止
- 🛡️ クリックジャッキングの防止
- 📡 中間者攻撃の防止
- 🚫 情報漏洩の防止
- ⚡ 信頼性の向上
主要なセキュリティヘッダー
1. Strict-Transport-Security (HSTS)
# HTTPSを強制する
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
max-age: HTTPS強制期間(秒)
includeSubDomains: サブドメインも含む
preload: HSTSプリロードリストに登録可能
メリット:
✅ HTTP→HTTPS自動リダイレクト
✅ SSL/TLS ストリッピング攻撃を防ぐ
✅ パフォーマンス向上(リダイレクト不要)2. Content-Security-Policy (CSP)
# XSS攻撃を防ぐ
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline';
ディレクティブ:
default-src: デフォルトポリシー
script-src: JavaScriptの読み込み元
style-src: CSSの読み込み元
img-src: 画像の読み込み元
connect-src: Ajax、WebSocketの接続先
font-src: フォントの読み込み元
例:
Content-Security-Policy:
default-src 'self';
script-src 'self' https://cdn.jsdelivr.net;
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
font-src 'self' https://fonts.gstatic.com;3. X-Frame-Options
# クリックジャッキング防止
X-Frame-Options: DENY
DENY: すべてのフレーム埋め込みを禁止
SAMEORIGIN: 同一オリジンのみ許可
ALLOW-FROM https://example.com: 特定のURLのみ許可(非推奨)
用途:
✅ iframeでの悪用防止
✅ UI redressing攻撃防止4. X-Content-Type-Options
# MIMEタイプスニッフィング防止
X-Content-Type-Options: nosniff
メリット:
✅ ブラウザがContent-Typeを尊重
✅ XSS攻撃のリスク軽減5. Referrer-Policy
# リファラー情報の制御
Referrer-Policy: strict-origin-when-cross-origin
no-referrer: リファラーを送信しない
no-referrer-when-downgrade: HTTPS→HTTPで送信しない
same-origin: 同一オリジンのみ
strict-origin: オリジンのみ送信
strict-origin-when-cross-origin: 推奨(デフォルト)6. Permissions-Policy
# ブラウザ機能の制御(旧Feature-Policy)
Permissions-Policy: geolocation=(), microphone=(), camera=()
制御できる機能:
- geolocation: 位置情報
- microphone: マイク
- camera: カメラ
- payment: 支払いAPI
- usb: USB
例:
Permissions-Policy:
geolocation=(self),
microphone=(),
camera=(self "https://trusted-site.com")Nginxでの設定
基本設定
# /etc/nginx/conf.d/security-headers.conf
server {
listen 443 ssl http2;
server_name example.com;
# SSL証明書
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# HSTS
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
# CSP
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:;" always;
# X-Frame-Options
add_header X-Frame-Options "SAMEORIGIN" always;
# X-Content-Type-Options
add_header X-Content-Type-Options "nosniff" always;
# Referrer-Policy
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# Permissions-Policy
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
location / {
root /var/www/html;
index index.html;
}
}共通設定ファイル
# /etc/nginx/snippets/security-headers.conf
# 複数のサーバーで再利用
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header Content-Security-Policy "default-src 'self';" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
# 使用方法
server {
listen 443 ssl http2;
server_name example.com;
include snippets/security-headers.conf;
location / {
root /var/www/html;
}
}Content-Security-Policyの詳細設定
段階的な導入
# Step 1: レポートモード(違反を検出するが適用しない)
Content-Security-Policy-Report-Only:
default-src 'self';
report-uri /csp-violation-report;
# Step 2: 違反レポートを確認
# ログを分析して必要なソースを追加
# Step 3: 本番適用
Content-Security-Policy:
default-src 'self';
script-src 'self' https://cdn.example.com;
report-uri /csp-violation-report;Google Analytics対応
Content-Security-Policy:
default-src 'self';
script-src 'self' https://www.googletagmanager.com https://www.google-analytics.com;
img-src 'self' https://www.google-analytics.com;
connect-src 'self' https://www.google-analytics.com;Google AdSense対応
Content-Security-Policy:
default-src 'self';
script-src 'self' 'unsafe-inline' https://pagead2.googlesyndication.com https://adservice.google.com;
img-src 'self' data: https:;
frame-src https://googleads.g.doubleclick.net;
style-src 'self' 'unsafe-inline';CSP違反レポートの受信
# Nginx設定
location /csp-violation-report {
access_log /var/log/nginx/csp-violations.log;
return 204;
}
# ログの確認
sudo tail -f /var/log/nginx/csp-violations.log
# 違反レポートの例
{
"csp-report": {
"document-uri": "https://example.com/page",
"violated-directive": "script-src",
"blocked-uri": "https://evil.com/malicious.js",
"original-policy": "default-src 'self';"
}
}HSTSプリロード
プリロードリストへの登録
要件:
1. 有効なHTTPS証明書
2. すべてのサブドメインでHTTPS
3. HSTSヘッダーの設定:
- max-age >= 31536000(1年)
- includeSubDomains
- preload
Nginx設定:
add_header Strict-Transport-Security
"max-age=31536000; includeSubDomains; preload" always;
登録:
https://hstspreload.org/ にアクセス
ドメインを入力して送信
効果:
✅ ブラウザが最初から自動的にHTTPS接続
✅ HTTP接続を一切行わないセキュリティヘッダーのテスト
オンラインツール
1. SecurityHeaders.com
https://securityheaders.com/
→ セキュリティスコア(A+が最高)
2. Mozilla Observatory
https://observatory.mozilla.org/
→ 詳細な分析とアドバイス
3. SSL Labs
https://www.ssllabs.com/ssltest/
→ SSL/TLS設定の評価curlでの確認
# すべてのヘッダー確認
curl -I https://example.com
# 特定のヘッダー確認
curl -I https://example.com | grep -i strict-transport
# 詳細表示
curl -v https://example.com 2>&1 | grep -i "< "
期待される出力:
Strict-Transport-Security: max-age=31536000; includeSubDomains
Content-Security-Policy: default-src 'self';
X-Frame-Options: SAMEORIGIN
X-Content-Type-Options: nosniffdocker-composeでの設定
Nginxコンテナの設定
# docker-compose.yml
version: '3.8'
services:
nginx:
image: nginx:alpine
ports:
- "443:443"
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./security-headers.conf:/etc/nginx/snippets/security-headers.conf:ro
- /etc/letsencrypt:/etc/letsencrypt:ro
restart: unless-stopped
# nginx.conf
http {
include /etc/nginx/snippets/security-headers.conf;
server {
listen 80;
server_name example.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
location / {
proxy_pass http://web:5000;
proxy_set_header Host $host;
}
}
}実用的な設定例
静的サイト(ブログ)
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' https://www.googletagmanager.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' https://fonts.gstatic.com;" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;Webアプリケーション
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; connect-src 'self'; frame-ancestors 'none';" always;
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer" always;
add_header Permissions-Policy "geolocation=(), microphone=(), camera=(), payment=()" always;API サーバー
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
add_header Content-Security-Policy "default-src 'none'; frame-ancestors 'none';" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer" always;
add_header X-Frame-Options "DENY" always;トラブルシューティング
CSPでサイトが壊れる
問題: スタイルやスクリプトが読み込まれない
解決:
1. ブラウザの開発者ツールでCSP違反を確認
2. 違反しているリソースを特定
3. CSPに追加
# Chrome DevTools > Console
Refused to load the script 'https://cdn.example.com/script.js'
because it violates the following Content Security Policy directive:
"script-src 'self'".
→ script-src に https://cdn.example.com を追加HSTSで開発環境にアクセスできない
問題: localhost でHTTPSを強制される
解決:
# Chrome
chrome://net-internals/#hsts
ドメインを入力 > Delete
# Firefox
about:preferences#privacy
Cookiesとサイトデータ > データを管理
ドメインを削除
予防:
開発環境ではHSTSを無効化まとめ
セキュリティヘッダーを正しく設定してWebサイトを保護しましょう。
必須ヘッダー
- Strict-Transport-Security(HSTS)
- Content-Security-Policy(CSP)
- X-Frame-Options
- X-Content-Type-Options
- Referrer-Policy
ベストプラクティス
- CSPはレポートモードから始める
- 段階的に厳格化
- 定期的にセキュリティスキャン
- HSTSプリロードリストに登録