HTTPセキュリティヘッダー完全ガイド
Webサーバーで設定すべき7つのHTTPセキュリティヘッダーを解説。各ヘッダーの役割、設定方法、Nginx/Djangoでの実装例を紹介する。
この記事の対象読者
- Webサーバーのセキュリティを強化したいインフラエンジニア
- セキュリティヘッダーの設定を体系的に理解したい方
- Nginx / Django でセキュリティヘッダーを設定したい方
- セキュリティ監査で指摘を受けた方
目次
Step 1セキュリティヘッダーとは
HTTPセキュリティヘッダーは、Webサーバーがレスポンスに付与するHTTPヘッダーで、ブラウザに対してセキュリティ関連の挙動を指示するものです。適切に設定することで、クリックジャッキング、MIMEスニッフィング、プロトコルダウングレード攻撃など、さまざまな攻撃を防ぐことができます。
多くのセキュリティヘッダーは1行の設定で追加でき、コストに対してリターンが大きいセキュリティ対策です。
ポイント: セキュリティヘッダーは「防御の層」を増やすものです。アプリケーション側のセキュリティ対策(入力検証、認証・認可など)を置き換えるものではありません。
Step 2X-Content-Type-Options
ブラウザがレスポンスのContent-Typeを無視して内容を推測(MIMEスニッフィング)することを防ぎます。例えば、テキストファイルがHTMLとして解釈されてスクリプトが実行される攻撃を防げます。
X-Content-Type-Options: nosniff設定値は nosniff の一択です。すべてのWebサイトで設定すべきヘッダーです。
| 設定値 | 効果 |
|---|---|
nosniff | Content-Typeヘッダーで宣言された型のみを使用する。MIMEスニッフィングを無効化 |
Step 3X-Frame-Options
ページがiframeやframe内に埋め込まれることを制御します。クリックジャッキング攻撃の防止に有効です。
X-Frame-Options: DENY| 設定値 | 効果 |
|---|---|
DENY | すべてのiframe埋め込みを禁止 |
SAMEORIGIN | 同一オリジンからの埋め込みのみ許可 |
補足: CSPの frame-ancestors ディレクティブはX-Frame-Optionsの上位互換です。両方設定している場合、CSP対応ブラウザでは frame-ancestors が優先されます。後方互換性のために両方設定するのが一般的です。
Step 4Strict-Transport-Security(HSTS)
ブラウザに対して、以降のアクセスでは必ずHTTPSを使用するよう指示します。HTTP→HTTPSリダイレクト時の中間者攻撃を防ぎます。
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload| パラメータ | 意味 |
|---|---|
max-age=31536000 | 1年間(秒単位)HTTPSを強制する |
includeSubDomains | サブドメインにも適用する |
preload | ブラウザのHSTSプリロードリストへの登録を許可する |
注意: HSTSを設定すると、max-ageの期間中はHTTPでのアクセスが不可能になります。HTTPS環境が完全に整っていることを確認してから設定してください。まずは max-age=300(5分)から始めることを推奨します。
Step 5Referrer-Policy
ページ遷移時にRefererヘッダーで送信される情報を制御します。URLにトークンやセッション情報が含まれている場合、外部サイトへの漏洩を防ぎます。
Referrer-Policy: strict-origin-when-cross-origin| 設定値 | 効果 |
|---|---|
no-referrer | Refererヘッダーを一切送信しない |
same-origin | 同一オリジンへのリクエストのみRefererを送信 |
strict-origin-when-cross-origin | 同一オリジンにはフルURL、クロスオリジンにはオリジンのみ送信(推奨) |
no-referrer-when-downgrade | HTTPS→HTTPのダウングレード時のみ送信しない(デフォルト) |
Step 6Permissions-Policy
ブラウザのAPI(カメラ、マイク、位置情報など)へのアクセスを制御します。不要な機能を無効化することで、攻撃面を減らせます。
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=()| 機能 | 設定例 | 意味 |
|---|---|---|
| カメラ | camera=() | すべてのオリジンで無効化 |
| マイク | microphone=() | すべてのオリジンで無効化 |
| 位置情報 | geolocation=(self) | 自オリジンのみ許可 |
| 決済 | payment=() | すべてのオリジンで無効化 |
Step 7X-XSS-Protection
ブラウザ組み込みのXSSフィルターを制御するヘッダーです。現在のモダンブラウザではXSSフィルター自体が廃止されているため、無効化するのが推奨です。
X-XSS-Protection: 0注意: 以前は 1; mode=block が推奨されていましたが、XSSフィルター自体に脆弱性が発見されたため、現在は 0(無効化)が推奨です。XSS対策にはCSPを使いましょう。
Step 8Cache-Control
機密情報を含むページではキャッシュを無効化し、ブラウザやプロキシにレスポンスを保存させないようにします。
Cache-Control: no-store, no-cache, must-revalidate, private| ディレクティブ | 効果 |
|---|---|
no-store | レスポンスを一切保存しない |
no-cache | キャッシュする前にサーバーに再検証を要求 |
must-revalidate | キャッシュ期限切れ後は必ず再検証 |
private | 共有キャッシュ(CDN、プロキシ)に保存しない |
Step 9Nginx / Django でまとめて設定
Nginx で全ヘッダーを設定
server {
# セキュリティヘッダー
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=()" always;
add_header X-XSS-Protection "0" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'" always;
}Django ミドルウェアで全ヘッダーを設定
class SecurityHeadersMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
response = self.get_response(request)
response["X-Content-Type-Options"] = "nosniff"
response["X-Frame-Options"] = "DENY"
response["Strict-Transport-Security"] = (
"max-age=31536000; includeSubDomains; preload"
)
response["Referrer-Policy"] = "strict-origin-when-cross-origin"
response["Permissions-Policy"] = (
"camera=(), microphone=(), geolocation=(), payment=()"
)
response["X-XSS-Protection"] = "0"
response["Content-Security-Policy"] = (
"default-src 'self'; "
"script-src 'self'; "
"style-src 'self' 'unsafe-inline'; "
"img-src 'self' data:; "
"font-src 'self'; "
"connect-src 'self'; "
"frame-ancestors 'none'"
)
return response確認方法: 設定後は securityheaders.com でスキャンして、すべてのヘッダーが正しく設定されているか確認しましょう。A+ 評価を目指してください。