Webアプリケーションの挙動や安全性、パフォーマンス、SEO、可観測性(デバッグしやすさ)を左右する要素のひとつが HTTPレスポンスヘッダー です。HTMLや画像、APIのレスポンス本文だけでなく、「そのコンテンツをブラウザやCDNがどう扱うべきか」「どこから読み込みを許可するか」「どれくらいキャッシュしてよいか」「どんな脅威を抑止するか」といった“取り扱い説明書”がヘッダーに集約されます。
本記事では、実運用で重要度が高い主要レスポンスヘッダーをカテゴリ別に整理し、何を制御し、どのように設定すべきか を具体例とともに解説します。
(注:HTTPヘッダーは環境・要件により最適解が変わります。本記事は一般的な推奨と、採用時の注意点を中心にまとめています。)
1. HTTPレスポンスヘッダーの全体像
レスポンスヘッダーは大きく以下の目的に分かれます。
- キャッシュ制御:ブラウザ・CDN・プロキシがどの程度保存してよいか
- コンテンツ表現:MIMEタイプ、文字コード、圧縮方式など
- セキュリティ:XSS/クリックジャッキング/情報漏えい/盗聴耐性など
- クロスオリジン制御:CORSやリソース分離
- Cookie管理:セッションや認証を安全に運ぶ
- 可観測性・運用:相関ID、サーバ情報、タイミングなど
- リダイレクト・ナビゲーション:Locationなど
また、HTTPヘッダーは 「ブラウザに対する指示」 である一方、CDNやロードバランサ、WAFなど中間層の動作にも影響します。特にキャッシュ系・セキュリティ系は、アプリだけでなく インフラ含めて一貫した設計 が重要です。
2. コンテンツ表現に関する基本ヘッダー
2.1 Content-Type
レスポンス本文の種類(MIMEタイプ) を表します。ブラウザはこれを見て、HTMLとして解釈するか、JSONとして扱うか、画像として表示するかを決めます。
- HTML:text/html; charset=UTF-8
- JSON:application/json; charset=UTF-8
- CSS:text/css; charset=UTF-8
- JS:application/javascript; charset=UTF-8
- 画像:image/png など
【推奨事項】
- 文字コードは原則 UTF-8 を明示
- APIは application/json を厳格に
Content-Type: text/html; charset=UTF-8
2.2 Content-Length
本文のバイト長。転送最適化や進捗表示、接続の扱いに使われます。多くはサーバやリバースプロキシが自動付与します。
2.3 Content-Encoding
圧縮方式を示します。代表は gzip、br(Brotli)、deflate。 CDNやWebサーバで自動圧縮するのが一般的です。
Content-Encoding: br
2.4 Vary
キャッシュの分岐条件 を指定します。これが適切でないと「圧縮済みを非対応ブラウザに返す」「言語が混ざる」などの事故が起きます。
- 圧縮:Vary: Accept-Encoding
- 言語:Vary: Accept-Language
Vary: Accept-Encoding
3. キャッシュ制御
3.1 Cache-Control
キャッシュの可否、期限、共有キャッシュ(CDN等)での扱いを指定します。
【主要ディレクティブ】
- no-store:保存禁止(機密ページ・個人情報)
- no-cache:保存してよいが 毎回再検証(ETag/Last-Modifiedと併用が多い)
- public / private:共有キャッシュに載せてよいか
- max-age=秒:ブラウザの有効期限
- s-maxage=秒:共有キャッシュ(CDN)の有効期限
- must-revalidate:期限切れ時に必ず再検証
【典型パターン(例)】
- (A) 静的アセット
app.3f2a1c.css のようにファイル名でバージョン管理できるなら、長期キャッシュが有利。
Cache-Control: public, max-age=31536000, immutable
- (B) HTML(ログインなしの公開ページ)
更新頻度があるなら短め + 再検証が無難。
Cache-Control: public, max-age=0, must-revalidate
- (C) 個人情報を含むページ(マイページ等)
保存そのものを避けたいなら
Cache-Control: no-store
3.2 ETag / If-None-Match
リソースの版(ハッシュのようなもの)を示し、クライアントが「同じなら本文不要(304)」を実現できます。帯域を節約し、体感を改善します。
ETag: "686897696a7c876b7e"
【注意点】
- 複数サーバ環境でETagがサーバ依存だと不整合になることがあります(生成方式に注意)。
- 静的アセットはファイル名ハッシュ運用のほうが管理が単純なことも多いです
3.3 Last-Modified / If-Modified-Since
更新日時ベースの再検証。ETagより粗いが実装が簡単なことが多いです。
3.4 Expires(旧来)
HTTP/1.0互換の期限指定。現在は Cache-Control が主役ですが、互換目的で併記されることがあります。
4. セキュリティ関連ヘッダー
4.1 Strict-Transport-Security(HSTS)
HTTPSを強制し、MITM(中間者攻撃)やダウングレードを抑止します。
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
【注意点】
- 一度有効化すると、max-age の間ブラウザはHTTPに戻せません。導入前にHTTPS完全移行を確認。
- includeSubDomains はサブドメインも全てHTTPSである必要があります。
- preload はブラウザのプリロードリスト申請が絡むため運用設計が必要です。
4.2 Content-Security-Policy(CSP)
XSSや不正な外部読み込みを強力に抑止します。 「どのオリジンからスクリプト・画像・CSS等を読み込んでよいか」を宣言します。
【基本例】
Content-Security-Policy: default-src 'self'; img-src 'self' https: data:; script-src 'self' https:; style-src 'self' https: 'unsafe-inline'
【理想に近づける方向性】
- インラインscriptを廃止して script-src 'self' 'nonce-...' へ
- object-src 'none' の明示
- base-uri 'self'、frame-ancestors 'none' 等の追加
4.3 X-Content-Type-Options: nosniff
MIMEスニッフィング(ブラウザが推測して別扱いする挙動)を抑止し、意図しないスクリプト実行を防ぎます。
X-Content-Type-Options: nosniff
4.4 X-Frame-Options / CSP frame-ancestors
クリックジャッキング対策。近年は frame-ancestors(CSP)推奨ですが、互換で X-Frame-Options を併用することもあります。
X-Frame-Options: DENY
Content-Security-Policy: frame-ancestors 'none'
4.5 Referrer-Policy
外部リンク遷移時に送るRefererの範囲を制御し、URLパラメータ等の漏えいを抑えます。
Referrer-Policy: strict-origin-when-cross-origin
4.6 Permissions-Policy(旧Feature-Policy)
ブラウザ機能(カメラ、マイク、位置情報等)の利用可否を制御します。不要な機能は閉じるのが基本です。
Permissions-Policy: camera=(), microphone=(), geolocation=()
4.7 Cross-Origin-Opener-Policy / Cross-Origin-Embedder-Policy / Cross-Origin-Resource-Policy
いわゆる「クロスオリジン分離」関連。高度な防御と、SharedArrayBuffer等の要件で必要になることがあります。
- Cross-Origin-Opener-Policy (COOP):別オリジンとのウィンドウ関係を制御
- Cross-Origin-Embedder-Policy (COEP):埋め込みリソースに追加条件
- Cross-Origin-Resource-Policy (CORP):他オリジンからの読み込み可否の方針
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Resource-Policy: same-origin
注意:これらは 外部ウィジェットや広告、CDN配信 と衝突しやすく、段階導入が重要です。
4.8 Set-Cookie
Cookieは認証・セッションに直結します。属性設定を誤ると、セッションハイジャックやCSRF、第三者送信の問題を引き起こします。
【重要属性】
- Secure:HTTPSでのみ送信
- HttpOnly:JSから読み取れない(XSS被害を減らす)
- SameSite:クロスサイト送信制御(CSRF対策)
- Lax:多くのWebでの現実的デフォルト
- Strict:より厳しい(外部遷移でログインが切れたように見える等)
- None:クロスサイト送信を許可(その場合 Secure 必須)
- Path / Domain:スコープ管理
- Max-Age / Expires:寿命
Set-Cookie: session=...; Path=/; Secure; HttpOnly; SameSite=Lax
5. CORS
5.1 Access-Control-Allow-Origin
ブラウザからのクロスオリジン呼び出し許可。APIを別ドメインから叩く場合に重要です。
-
- は「資格情報(Cookie等)なし」に限り安全側で使えることがあります
- 認証付きなら 特定オリジンを明示 し、Vary: Origin を付けるのが基本
Access-Control-Allow-Origin: https://example.com
Vary: Origin
5.2 Access-Control-Allow-Credentials
Cookieなどの資格情報を送る場合
Access-Control-Allow-Credentials: true
注意:この場合 Allow-Origin: * は使えません。
5.3 Access-Control-Allow-Methods / Access-Control-Allow-Headers
プリフライト(OPTIONS)応答で必要になります。
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization
6. リダイレクト・場所・認証
6.1 Location
3xx(リダイレクト)や201 Created等で、移動先や新規作成リソースを示します。
HTTP/1.1 301 Moved Permanently
Location: https://example.com/new-path
6.2 WWW-Authenticate
401 Unauthorizedで、認証方式(Basic/Bearer等)を示します。
WWW-Authenticate: Bearer realm="api"
7. 可観測性・運用
7.1 Date
レスポンス生成時刻。多くは自動付与されます。
7.2 Server
サーバ情報(例:nginx、Apache)。攻撃者にヒントを与える 場合があるため、最小化・非表示を検討する運用もあります(ただし完全秘匿の効果は限定的で、優先度は中〜低)。
7.3 X-Request-Id
アプリ〜LB〜ログ基盤まで一貫して追跡するための相関ID。 障害時に「この画面のリクエストがログのどれか」を即座に辿れるようになります。
X-Request-Id: 8b2c9d2f-1b0f-4b5d-9f2a-...
7.4 Server-Timing
パフォーマンス測定情報をブラウザへ返し、DevToolsで可視化できます。 DB時間、キャッシュヒット、外部API時間などを区別できると改善が早まります。
Server-Timing: app;dur=35.2, db;dur=12.7, cache;desc="hit";dur=1.1
8. 代表的なレスポンス例
8.1 公開HTML(例:記事ページ)
Content-Type: text/html; charset=UTF-8
Cache-Control: public, max-age=0, must-revalidate
ETag: "abc123"
Vary: Accept-Encoding
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
X-Frame-Options: DENY
Content-Security-Policy: default-src 'self'; img-src 'self' https: data:; script-src 'self' https:; style-src 'self' https: 'unsafe-inline'
8.2 認証が絡む個人ページ(例:マイページ)
Content-Type: text/html; charset=UTF-8
Cache-Control: no-store
Vary: Accept-Encoding
Set-Cookie: session=...; Path=/; Secure; HttpOnly; SameSite=Lax
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
X-Frame-Options: DENY
8.3 API(例:JSON)
Content-Type: application/json; charset=UTF-8
Cache-Control: no-store
Vary: Accept-Encoding, Origin
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Credentials: true
X-Content-Type-Options: nosniff
静的アセット(ハッシュ付き)
Content-Type: text/css; charset=UTF-8
Cache-Control: public, max-age=31536000, immutable
Vary: Accept-Encoding
X-Content-Type-Options: nosniff
まとめ:まず押さえるべき優先順位
P0(ほぼ必須)
- Content-Type
- Cache-Control(ページ種別ごとに)
- Strict-Transport-Security(HTTPS完全移行後)
- X-Content-Type-Options: nosniff
- Set-Cookie の Secure/HttpOnly/SameSite
P1(強く推奨)
- Content-Security-Policy(段階導入でも)
- Referrer-Policy
- X-Frame-Options(またはCSP frame-ancestors)
- Vary: Accept-Encoding(圧縮運用時)
- ETag / Last-Modified(再検証で帯域削減)
P2(要件次第で有効)
- CORS系(Access-Control-*)
- Permissions-Policy
- COOP/COEP/CORP
- Server-Timing、X-Request-Id