HTTPセキュリティヘッダ・Cookie属性#
1. 脆弱性の概要 / 影響#
クロスサイトスクリプティング(XSS)、セッションハイジャック、クリックジャッキング等の攻撃を防御するメカニズムであるHTTPセキュリティヘッダ(HSTS、CSP、X-Frame-Options等)やCookie属性(Secure、HttpOnly、SameSite)を設定することはシステムの安全性を確保するうえで重要であるにもかかわらず、セキュリティ診断の実施後にこれらの不備が指摘されるケースがしばしば見受けられます。
これらのセキュリティ機構はリスクの『軽減』を目的とした多層防御の一部であり、アプリケーション側の脆弱性(不適切なエスケープ等)そのものを排除するものではないことに注意してください。緩和策の実施後もリスクは残存し、恒久的な対策への移行を計画・実行する必要があります。
HTTPセキュリティヘッダ欠如のリスク#
| ヘッダ | 目的 | 欠如時のリスク |
|---|---|---|
| Strict-Transport-Security (HSTS) | HTTPS接続の強制 | 中間者がHTTPS接続をHTTPにダウングレードし、通信内容を盗聴・改ざん可能 |
| Content-Security-Policy (CSP) | リソース読み込み制限 | XSS攻撃による悪意あるスクリプトの実行、データ窃取、フィッシング等の被害拡大 |
| X-Frame-Options | クリックジャッキング防止 | 悪意あるサイトにiframeで埋め込まれ、ユーザーの意図しない操作を誘発される |
| X-Content-Type-Options | MIMEスニッフィング防止 | ブラウザのMIMEタイプ推測により、悪意あるファイルが意図しない形式で実行される |
| Referrer-Policy | Referer情報の制御 | 機密情報を含むURLが外部サイトに漏洩 |
Cookie属性欠如のリスク#
| 属性 | 目的 | 欠如時のリスク |
|---|---|---|
| Secure | HTTPS通信でのみCookie送信 | 中間者攻撃により、HTTP通信経由でCookieが窃取され、セッションハイジャックされる |
| HttpOnly | JavaScriptからのCookieアクセス禁止 | XSS攻撃により、認証Cookieが窃取され、なりすましや権限昇格が可能になる |
| SameSite | クロスサイトリクエストでのCookie送信制御 | CSRF攻撃により、ユーザーの意図しない操作が実行される(パスワード変更、送金等) *1 |
*1 Google Chrome や Microsoft Edge 等のモダンブラウザでは、SameSite 属性が省略された Cookie に対しても
SameSite=Lax相当の挙動がデフォルトで適用されるため、クロスサイトの POST リクエストでは Cookie が送信されないなど、限定的ながらブラウザによる CSRF 保護を受けられます。
CookieのSameSite属性の間違えやすい挙動#
SameSite 属性は仕様が複雑で、ブラウザにより挙動が異なります。たとえば Chromium 系のブラウザでは、SameSite 属性が明示されていない Cookie に対してデフォルトで SameSite=Lax 相当が適用されますが、Cookie がブラウザに保存されてから 2 分間 は例外的にクロスサイトの POST リクエストでも送信される仕様があります。
一方 Firefox では SameSite 属性が明示されていない Cookie に対するデフォルト保護が存在しないため、開発者が明示的に SameSite=Lax または SameSite=Strict を設定しない限り CSRF 保護を受けられません。
以下は、SameSite属性の制御によりCookieが送信されるかをまとめた表です。「✓」がマークされている箇所がクロスサイトから送信されるパターンを示しています。
SameSite属性の有無によるCookieの挙動(Chromium 系)#
| 送信方法 | Strict | Lax(明示) | default (属性なし) | None |
|---|---|---|---|---|
| ① クロスサイトからのGETリクエスト(リンク) | ✗ | ✓ | ✓ | ✓ |
| ② クロスサイトからのPOSTリクエスト(フォーム)<2分以内> | ✗ | ✗ | ✓ | ✓ |
| ② クロスサイトからのPOSTリクエスト(フォーム)<2分超過> | ✗ | ✗ | ✗ | ✓ |
| ③ クロスサイトから読み込まれるサブリソース(iframe 等) | ✗ | ✗ | ✗ | ✓ |
SameSite属性の有無によるCookieの挙動(Firefox)#
Firefox には「SameSite 属性が省略された Cookie をデフォルトで SameSite=Lax 相当として扱う」設定 (network.cookie.sameSite.LaxByDefault) が存在しますが、現在も既定で無効 になっています。そのため SameSite 属性を省略した Cookie は None と同等に扱われ、判定はシンプルになる一方で、SameSite 属性が未指定の Cookie は CSRF 保護を一切受けられない 点に注意が必要です。
| 送信方法 | Strict | Lax(明示) | default (属性なし) | None |
|---|---|---|---|---|
| ① クロスサイトからのGETリクエスト(リンク) | ✗ | ✓ | ✓ | ✓ |
| ② クロスサイトからのPOSTリクエスト(フォーム) | ✗ | ✗ | ✓ | ✓ |
| ③ クロスサイトから読み込まれるサブリソース(iframe 等) | ✗ | ✗ | ✓ | ✓ |
Chromium 系との主な違い
default(属性なし)列がNoneと同じ挙動になる(太字部分)- POST の判定に時間的な例外が無い
また、多層防御を実現するための方法として、Cookie名を設定する際の接頭辞(Prefix)があります。これらの設定を使用することで、属性値の設定忘れを防ぎ、より安全なシステムを実現できます。
| Prefix | 目的 |
|---|---|
| __Host- | Secure・Path=/の属性が必須・Domain属性の禁止 |
| __Secure- | Secure 属性を必須化して、HTTPSでのみ送信されるCookieにする(平文HTTPへの送信をブラウザ側で防ぐ) |
ブラウザ毎にCookieの振る舞いは異なるため、Cookieに依存した実装を行う場合は必ず各ブラウザのリリースを見て確認してください。
2. 根本的な対策#
HTTPセキュリティヘッダの適切な設定#
理想的には、Webアプリケーションまたはリバースプロキシ(Nginx、Apache等)で以下のヘッダを設定します。
(HTTPレスポンスヘッダ)
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-originOWASP HTTP Headers Cheat Sheet では、これらのヘッダを「ブラウザに対するセキュリティポリシーの強制」として位置づけています。
Cookie属性の適切な設定#
認証・セッション管理に使用するCookieには、以下の属性を設定します:
Set-Cookie: sessionId=xxx; Secure; HttpOnly; SameSite=Strict; Path=/; Max-Age=3600IPA「安全なウェブサイトの作り方」では、セッションIDをCookieに格納する場合、Secure属性とHttpOnly属性の付与を推奨しています。
3. 起こり得るケースと緩和策#
実際の開発・運用現場では以下のような制約により、これらの対策が即時実施できないケースが存在します。
- 共通基盤への依存: 組織の共通基盤(AWS ALB等のロードバランサー)が生成するCookieの属性を制御できない
- アーキテクチャの制約: バックエンドがHTTP通信のため、Secure属性の付与が困難
- 機能要件との衝突: クライアントサイドJavaScriptでCookieにアクセスする必要があり、HttpOnlyが原理的に不可
- 影響範囲の不明確性: 多くのサービスが依存しており、変更による影響を特定できない
以降では、いくつかのケースでの緩和策を紹介します。
ケース①#
組織の共通基盤として導入されているロードバランサー(AWS ALB等)やCDN(CloudFront等)が生成するCookieの属性を、アプリケーション側から制御できず、ブラウザのXSSやCSRF保護を受けられない場合。
具体的な例:
- AWS ALBが生成する
AWSALBCookieは、Sticky Session用に暗号化された情報を含むが、HttpOnlyフラグを設定する機能を提供していない - このCookieがWebサーバーに渡ると、Webサーバーがそれを理解できず、ロードバランサーによるセッション維持が機能しなくなる可能性がある
ケース①の緩和策#
AWSALB のような共通基盤生成 Cookie に HttpOnly や SameSite を付与できない場合、本来これらの属性で抑止していた XSS による Cookie 窃取 と CSRF によるなりすましリクエスト の 2 つの攻撃経路が露出します。Cookie 属性に頼れない以上、これらの攻撃そのものを WAF とアプリケーション側の両面から抑える方針に切り替えます。
(A) WAF/シグネチャによる XSS 対策
Web Application Firewall(WAF)を導入し、クエリパラメータやリクエストボディに含まれる XSS ペイロードを検知・遮断します。WAF はアプリケーション層(Layer 7)で動作し、HTTP ヘッダ・Cookie・リクエストボディを検査して攻撃トラフィックを遮断できます。
(B) アプリケーション側での CSRF 対策
SameSite 属性で守れない以上、CSRF トークンによるリクエスト検証を必ず実装します。Laravel や Next.js 等の主要フレームワークには CSRF 対策機能が標準搭載されているため、フレームワーク標準の機能を利用するのが確実です。
ケース②#
ロードバランサー(ALB等)とバックエンドWebサーバー間の通信がHTTP(非暗号化)で行われている場合、WebサーバーはSecure属性を持つCookieを発行できない。(一部のシステムで内部通信の暗号化処理によるオーバーヘッドを避けるため、意図的にHTTPを使用しているケースで発生)
具体的な例:
- ALBはHTTPSでクライアントと通信
- ALBとバックエンド間はHTTP通信(パフォーマンス向上のため)
- Webサーバーが発行するCookieにSecure属性を付与できない
ケース②の緩和策#
セッション管理の見直し
- トークンベース認証への移行: Cookieではなく、Authorizationヘッダでのトークン送信に変更し、セッションに使用しているトークンの有効期限を短くします。
- リフレッシュトークンをブラウザに保存する: Authorizationヘッダで送信するトークンの有効期限が切れた場合は、ブラウザのCookie領域に保存されたリフレッシュトークンを送信し、セッションの再発行を行います。(その際にリフレッシュトークンも更新する)
残存リスク#
- 中間者攻撃: ネットワークに侵入した攻撃者や内部犯によりバックエンド間のHTTP通信が盗聴されると、Cookieが平文で漏洩する可能性がある
- 設定ミス: フロントエンドでの属性付与設定が不完全・誤設定の場合、防御効果が十分に得られない可能性がある
ケース③#
JavaScriptからCookieにアクセスする必要がある機能(UI設定の保存、クライアントサイドのトラッキング等)では、HttpOnly属性を付与できない。これは、HttpOnlyが「JavaScriptからのアクセス禁止」を目的としているため、機能要件と根本的に矛盾する。
具体的な例:
- ユーザーが選択したUIの設定をCookieに保存
- 言語設定の保存
- クライアントサイドでのセッション管理
ケース③の緩和策#
(A) Cookieの用途分離
セキュリティ上重要なCookie(認証トークン、セッションID等)と、クライアントサイドで使用するCookieを分離する:
| Cookie種別 | 属性 | 用途 |
|---|---|---|
| 認証Cookie | Secure; HttpOnly; SameSite=Strict | セッション管理(JavaScriptからアクセス不可) |
| 設定Cookie | Secure; SameSite=Lax | UI設定等(JavaScriptからアクセス可能) |
(B) 代替ストレージの検討
セキュリティ上重要でないデータについては、Cookie以外のストレージ利用を検討してください。
- localStorage/sessionStorage: クライアントサイドのみで使用するデータ
- IndexedDB: 構造化データの保存
ただし、これらのストレージはXSS攻撃により窃取されるリスクがあるため、機密情報の保存には使用しないでください。特に、メールアドレス等のユーザー由来の情報の取り扱いに気をつけてください。
(C) XSS対策の強化
HttpOnlyが使用できない場合、XSS攻撃のリスクが高まるため、以下の対策を徹底します。
- Content Security Policy(CSP)の厳格化:
script-src 'self'等の制限を設ける - 出力時のエンコーディング: すべての動的コンテンツに対して適切なエスケープ処理を実施
- Trusted Types: 信頼できない文字列からのDOM操作を制限
ケース④#
多くのサービス・システムが相互に依存しており、Cookie属性やHTTPヘッダの変更がどのサービスに影響を与えるか特定が困難な場合がある。特に、長年運用されているシステムや、マイクロサービスアーキテクチャでは、この問題が顕著です。
ケース④の緩和策#
(A) 段階的なロールアウト
- カナリアリリース: 一部のユーザー・サービスにのみ変更を適用し、影響を監視します。
- Feature Flag: 設定変更をFeature Flagで制御し、問題発生時に即座にロールバック可能にする。
(B) テスト環境での検証強化
- 統合テストの充実: 依存サービスを含めたエンドツーエンドのテストを実施
- Shadow Traffic: 本番トラフィックをテスト環境にミラーし、実環境に近い状態で検証
4. 緩和策実施後も残存するリスク#
上記の各緩和策を講じたとしても、リスクは残存します。本章の冒頭部分でも触れていますが、 これらのセキュリティ機構はリスクの「軽減」が目的であり、「根本解決」ではありません。いずれも一時的な防御手段であり、脆弱性そのものを排除するものではないことに注意してください。 また、緩和策を導入した後に、リスクの根本解決を図ることが重要です。特に、脆弱性診断などで検出された問題に対してHTTPセキュリティヘッダやCookie属性といった「暫定対策」をいつまでも行ってしまい、根本対策が実施されないリスクが存在するということも理解しておく必要があります。
脆弱性診断などの報告書では、継続的にリスクを明確化しておくことができます。
- 現状の詳細な記録: どのCookieにどの属性が欠如しているか、なぜ設定できないかを具体的に記載
- リスクの定量化: CVSSスコア等を用いて、欠如している属性に起因するリスクを評価
- 影響範囲の明示: どのような攻撃シナリオで悪用可能か、被害の想定範囲を記載
- 経時的な追跡: 毎年の診断で同じ指摘を継続することで、リスク受容の事実を可視化
セキュリティ診断における継続的な指摘の意義 例年同じ指摘が検出される場合においても「クロスサイトスクリプティングによる画面改ざんや、CookieのSecure属性不備による情報漏洩等で、何かしらの影響があります」と顧客へ報告することで、保険的な意味合いを持たせることができます。また、開発者が普段見ないHTTPヘッダに気づくきっかけとなり、社内ポリシーとの乖離を発見できる可能性があります。
診断で繰り返し指摘されることは、単なる「未修正の露呈」ではなく、「許容したリスクが現在も許容可能な範囲内に収まっているか」を定期的に再評価するプロセスとして機能します。また、開発チームに対してセキュアコーディング意識を維持させる「ガードレール」としての役割も果たします。
5. 出典・参考文献#
- HTTP Security Response Headers Cheat Sheet https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html
- 「安全なウェブサイトの作り方」改訂第7版 https://www.ipa.go.jp/security/vuln/websecurity/about.html