HTTPセキュリティヘッダーの設定方法|Webサイトを攻撃から守る
Content-Security-Policy、X-Frame-Options、HSTSなど、重要なHTTPセキュリティヘッダーの役割と設定方法を解説します。
HTTPセキュリティヘッダーは、Webサイトを様々な攻撃から守るための重要な設定です。適切に設定することで、XSSやクリックジャッキングなどの攻撃リスクを大幅に軽減できます。
セキュリティヘッダーとは
HTTPレスポンスに含まれるヘッダーで、ブラウザにセキュリティ関連の指示を与えます。
HTTP/1.1 200 OK
Content-Type: text/html
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Content-Security-Policy: default-src 'self'
主要なセキュリティヘッダー
1. Strict-Transport-Security(HSTS)
HTTPSを強制し、中間者攻撃を防ぎます。
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
| パラメータ | 説明 |
|---|---|
| max-age | HTTPS強制の期間(秒) |
| includeSubDomains | サブドメインにも適用 |
| preload | ブラウザのプリロードリストに登録 |
設定例(Nginx):
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
設定例(Apache):
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
設定例(Next.js):
// next.config.js
module.exports = {
async headers() {
return [
{
source: '/:path*',
headers: [
{
key: 'Strict-Transport-Security',
value: 'max-age=31536000; includeSubDomains'
}
]
}
]
}
}
2. Content-Security-Policy(CSP)
読み込み可能なリソースを制限し、XSS攻撃を防ぎます。
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com; style-src 'self' 'unsafe-inline'
主要なディレクティブ:
| ディレクティブ | 対象 |
|---|---|
| default-src | デフォルトのソース |
| script-src | JavaScript |
| style-src | CSS |
| img-src | 画像 |
| font-src | フォント |
| connect-src | Ajax、WebSocket |
| frame-src | iframe |
| object-src | Flash等のプラグイン |
値の指定方法:
| 値 | 意味 |
|---|---|
| 'self' | 同一オリジン |
| 'none' | 全て禁止 |
| 'unsafe-inline' | インラインスクリプト許可 |
| 'unsafe-eval' | eval()許可 |
| https: | HTTPS経由のみ |
| https://example.com | 特定ドメイン |
段階的な導入:
# まずレポートモードで影響を確認
Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report
# 問題なければ本番適用
Content-Security-Policy: default-src 'self'
3. X-Frame-Options
クリックジャッキング攻撃を防ぎます。
X-Frame-Options: DENY
| 値 | 意味 |
|---|---|
| DENY | iframeでの表示を完全に禁止 |
| SAMEORIGIN | 同一オリジンからのみ許可 |
| ALLOW-FROM uri | 特定のURIからのみ許可(非推奨) |
注意: CSPの
frame-ancestorsディレクティブがより推奨されます。
Content-Security-Policy: frame-ancestors 'self'
4. X-Content-Type-Options
MIMEタイプのスニッフィングを防ぎます。
X-Content-Type-Options: nosniff
これにより、ブラウザがContent-Typeを推測せず、指定された通りに解釈します。
5. Referrer-Policy
リファラー情報の送信を制御します。
Referrer-Policy: strict-origin-when-cross-origin
| 値 | 意味 |
|---|---|
| no-referrer | リファラーを送信しない |
| origin | オリジンのみ送信 |
| same-origin | 同一オリジンのみ送信 |
| strict-origin-when-cross-origin | 推奨設定 |
6. Permissions-Policy(旧Feature-Policy)
ブラウザ機能の使用を制限します。
Permissions-Policy: camera=(), microphone=(), geolocation=(self)
| 機能 | 説明 |
|---|---|
| camera | カメラ |
| microphone | マイク |
| geolocation | 位置情報 |
| payment | 決済API |
| usb | USB |
推奨設定
基本的なセキュリティヘッダーセット
# Nginx設定例
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
Next.js/Vercelでの設定
// next.config.js
const securityHeaders = [
{
key: 'Strict-Transport-Security',
value: 'max-age=31536000; includeSubDomains'
},
{
key: 'X-Content-Type-Options',
value: 'nosniff'
},
{
key: 'X-Frame-Options',
value: 'DENY'
},
{
key: 'Referrer-Policy',
value: 'strict-origin-when-cross-origin'
}
];
module.exports = {
async headers() {
return [
{
source: '/:path*',
headers: securityHeaders,
},
];
},
};
セキュリティヘッダーの確認方法
ブラウザの開発者ツール
- サイトにアクセス
- F12で開発者ツールを開く
- Network → リクエストを選択 → Headers
コマンドライン
curl -I https://example.com
オンラインツール
- SecurityHeaders.com: https://securityheaders.com/
- Observatory by Mozilla: https://observatory.mozilla.org/
RiskLensで確認
RiskLensでドメインを診断すると、セキュリティヘッダーの設定状況を自動でチェックし、不足しているヘッダーを指摘します。
よくある問題と対処法
CSPでサイトが壊れる
原因: インラインスクリプトやサードパーティリソースがブロックされる
対処法:
Content-Security-Policy-Report-Onlyでテスト- 必要なソースを追加
- インラインスクリプトをnonceまたはhashで許可
Content-Security-Policy: script-src 'self' 'nonce-abc123'
<script nonce="abc123">
// インラインスクリプト
</script>
HSTSでHTTPサイトにアクセスできなくなる
原因: max-ageが長く設定され、HTTPSが利用できなくなった
対処法:
- 最初は短いmax-age(86400=1日)で設定
- 問題なければ徐々に延長
iframeが表示されない
原因: X-Frame-OptionsまたはCSP frame-ancestorsの制限
対処法:
- 必要なオリジンを許可
SAMEORIGINまたはframe-ancestors 'self'を使用
チェックリスト
- HSTSが設定されている
- X-Content-Type-Optionsが設定されている
- X-Frame-Optionsが設定されている
- Referrer-Policyが設定されている
- CSPが設定されている(または検討中)
- Permissions-Policyで不要な機能を無効化
まとめ
| ヘッダー | 対策する攻撃 | 優先度 |
|---|---|---|
| HSTS | 中間者攻撃 | 高 |
| X-Content-Type-Options | MIMEスニッフィング | 高 |
| X-Frame-Options | クリックジャッキング | 高 |
| CSP | XSS | 中〜高 |
| Referrer-Policy | 情報漏洩 | 中 |
| Permissions-Policy | 機能悪用 | 低〜中 |
セキュリティヘッダーは、サーバー設定一つで導入できる効果的な対策です。RiskLensで現在の設定状況を確認し、不足しているヘッダーを追加しましょう。