Webセキュリティ

HTTPセキュリティヘッダー完全ガイド — 設定すべき7つのヘッダー

セキュリティ HTTP Web

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サイトで設定すべきヘッダーです。

設定値効果
nosniffContent-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=315360001年間(秒単位)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-referrerRefererヘッダーを一切送信しない
same-origin同一オリジンへのリクエストのみRefererを送信
strict-origin-when-cross-origin同一オリジンにはフルURL、クロスオリジンにはオリジンのみ送信(推奨)
no-referrer-when-downgradeHTTPS→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 で全ヘッダーを設定

nginx.conf
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 ミドルウェアで全ヘッダーを設定

middleware.py
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+ 評価を目指してください。