結論(CookieのHttpOnly属性)
CookieのHttpOnly属性とは、Set-Cookieに付ける属性で、そのCookieをブラウザ上のJavaScript(document.cookieなど)から読み取れなくするものです。サイトにXSSの脆弱性があり攻撃スクリプトが実行されても、セッションIDを外部へ盗み出されることを防ぐ「保険」になります。ただしXSSによる操作そのものは防げないため、出力時のエスケープやCSPと組み合わせます。
この記事のポイント
- HttpOnly付きCookieはdocument.cookieから読めませんが、fetch()やXMLHttpRequestを含む通常のリクエストには送信されます。
- 防げるのは「Cookieの値の持ち出し」で、XSSでなりすまし操作されることは防げません。
- CSRFトークンのダブルサブミットや表示設定など、JavaScriptが読む必要のあるCookieはHttpOnlyにできません。
- 診断ではHttpOnlyなしのCookieが1件でもあれば△(重み3×0.45)とし、セッションIDかどうかの確認を促します。
- PHPSESSID・JSESSIONIDなどのセッションIDには必ずHttpOnlyを付け、サーバー側ではTRACEも無効化します。
| 診断項目名 | CookieのHttpOnly属性 |
|---|---|
| 項目ID | cookie.httponly |
| 分類 | Cookie・セッション管理 |
| 重大度・配点の重み | 重要(high) 重み 3 |
| 関連する標準・ガイドライン | OWASP ASVS 5.0.0 V3.3.4(Level 2)/OWASP WSTG-SESS-02(Testing for Cookies Attributes)/IPA「安全なウェブサイトの作り方」1.5 XSS 対策 5-(ix)(HttpOnly属性とTRACE無効化)/CWE-1004(Sensitive Cookie Without 'HttpOnly' Flag) |
CookieのHttpOnly属性とは
CookieのHttpOnly属性とは、サーバーが Set-Cookie ヘッダーで発行するCookieに付ける属性で、そのCookieをブラウザ上のJavaScriptから document.cookie などで読み取れなくするものです。
Set-Cookie: PHPSESSID=…; path=/; secure; HttpOnly; SameSite=Lax
サイトにクロスサイト・スクリプティング(XSS)の脆弱性があり、攻撃者のスクリプトが実行されてしまった場合でも、HttpOnly属性があればセッションIDを外部に盗み出されることを防げます。XSS対策の「保険」の役割を果たす属性です。
OWASP ASVS 5.0.0 は V3.3.4(Level 2)で「クライアント側スクリプトから参照される必要がないCookie(セッショントークンなど)には HttpOnly 属性を設定すること」を求めています。IPAもXSSの保険的対策として「発行するCookieにHttpOnly属性を加え、TRACEメソッドを無効化する」(5-(ix))を挙げています。
HttpOnly属性の仕組みと防げること・防げないこと
ブラウザの動作
HttpOnly付きCookieはdocument.cookieの読み書き対象から除外されます。- それでもCookie自体は通常どおり送信されます。MDNが説明しているとおり、JavaScriptから発行した
fetch()やXMLHttpRequestのリクエストにも付与されます。 - つまり
HttpOnlyは「Cookieの値を盗まれること」を防ぐものであり、「XSSで利用者になりすまして操作されること」は防げません。XSSそのものの対策(出力時のエスケープ、CSP)が本筋です。
HttpOnlyを付けられないCookieがある
すべてのCookieが HttpOnly にできるわけではありません。
- CSRF対策の「ダブルサブミット」方式では、JavaScriptがCookieのトークンを読んでリクエストヘッダーに付ける必要があります(例:Angularの
XSRF-TOKEN)。 - 文字サイズ・配色・言語切替など、画面表示の設定をJavaScriptで読む用途のCookieもあります。
ASVSも「スクリプトから参照される必要がないCookie」に限定して要件を定めています。このためセキュリティAIチェッカーは、HttpOnlyの無いCookieがあっても直ちに「要改善」とはせず「要確認(warn)」とし、そのCookieがセッションIDなどの機密値でないかを確認するよう促します。
TRACEメソッドとの関係(Cross-Site Tracing)
かつては、HTTPの TRACE メソッドがリクエストをそのまま反射する性質を使い、HttpOnly Cookieを読み出す手法(Cross-Site Tracing)が知られていました。現在の主要ブラウザはスクリプトからのTRACE送信を禁止していますが、IPAはサーバー側でもTRACEを無効化することを推奨しています。
CookieのHttpOnly属性についてよくある誤解
- 「HttpOnlyならXSSは怖くない」:攻撃スクリプトは利用者のブラウザ内で、Cookieを読まずにそのまま申請・設定変更などの操作を実行できます。
- 「アクセス解析Cookieもすべて対象」:Google Analyticsの
_gaなどはJavaScriptが設定・参照するためHttpOnlyにできません。これらはJavaScriptで設定されるため、この診断(Set-Cookieヘッダーのみを観測)では検出されません。
CookieのHttpOnly属性の診断基準(セキュリティAIチェッカー)
取得方法
- トップページ(転送後の最終応答)と、トップページ内の同一オリジンリンクから選んだ最大4ページ(ログイン・管理・マイページ系を優先)を GETのみ で取得します。ログアウト・削除系のURLや静的ファイルは巡回しません。
- 各最終応答の
Set-Cookieヘッダーを1件ずつ収集します。転送途中の応答のCookieは観測しません。 - 削除用のSet-Cookie(
Max-Age=0以下、または過去のExpires)は除外します。 - 有効なCookieが0件なら対象外(na)とします。
判定条件
| 判定 | 条件 | 得点への影響 |
|---|---|---|
| ○ 問題なし(pass) | 観測した有効なCookieすべてに HttpOnly 属性がある | 重み3 × 1.00 |
| △ 要確認(warn) | HttpOnly 属性のないCookieが1件以上ある | 重み3 × 0.45 |
| 対象外(na) | 有効なCookieを観測できなかった(結果には重大度high・重み3のまま記録) | 得点計算から除外 |
| × 要改善(fail) | 使用しません | ― |
- 属性の検出は「
;の後に属性名HttpOnly(大文字小文字を区別しない)があり、その直後が;・=・行末のいずれか」という条件で行います。 - 根拠欄には確認したCookie件数を表示し、値は表示しません。
- 公開情報だけでは「そのCookieをJavaScriptが読む必要があるか」を判断できないため、×ではなく△としています。△の場合は、該当Cookieの名前を開発者ツールで確認し、セッションIDや認証トークンであれば必ず
HttpOnlyを付けてください。
△(要確認)になったときの確認手順
- ブラウザの開発者ツール(Application → Cookies)で、HttpOnly列にチェックの無いCookieの名前を確認します。
- 名前から用途を推定します。
PHPSESSID・JSESSIONID・ASP.NET_SessionId・connect.sid・laravel_sessionなどはセッションIDであり、HttpOnlyが必須です。 - 名前だけで判断できない場合は、サイトのJavaScript(
document.cookieを参照している箇所)を検索し、そのCookieを読んでいるかを確認します。読んでいなければHttpOnlyを付けます。 - JavaScriptが読む必要があるCookieは、値に個人情報や認証情報を含まないことを確認し、その理由を設計書に記録しておくと、次回の診断で説明しやすくなります。
自治体サイトでの判定例
| 観測したSet-Cookie | 判定 |
|---|---|
PHPSESSID=…; path=/; secure; HttpOnly; SameSite=Lax | ○ |
JSESSIONID=…; Path=/; Secure(HttpOnlyなし) | △(セッションIDなので実質的に要修正) |
fontsize=large; Path=/; Secure(文字サイズ切替用) | △(JavaScriptが読む用途なら許容可) |
| Cookieの発行なし | 対象外 |
HttpOnly属性がないとどんなリスクがあるか
- XSSによるセッションID窃取:攻撃者が掲示板・問い合わせ結果表示・検索結果ページなどのXSSを利用し、
document.cookieを外部サーバーへ送信させることで、利用者のセッションを乗っ取ります(CWE-1004)。HttpOnlyはこの「値の持ち出し」を防ぎます。 - 長期的ななりすまし:盗んだセッションIDは、セッションが有効な間、攻撃者自身の端末から利用できます。HttpOnlyが無い場合、XSSの影響は「その場の操作」から「継続的ななりすまし」へ拡大します。
- 自治体での想定被害:電子申請・施設予約・職員用CMSのセッションが盗まれると、申請内容(氏名・住所・連絡先)の閲覧、なりすまし予約、公式サイトの改ざんにつながります。
CookieのHttpOnly属性の設定方法(PHP・Apache・nginx・IIS・Java・Next.js)
PHP
<?php
// php.ini / .user.ini
// session.cookie_httponly = 1
// 個別のCookie(PHP 7.3以降)
setcookie('member_token', $token, [
'path' => '/',
'secure' => true,
'httponly' => true,
'samesite' => 'Lax',
]);
Apache(補助策)
<IfModule mod_headers.c>
Header always edit Set-Cookie "(?i)^(?!.*;\s*httponly\s*(?:[;=]|$))(.*)$" "$1; HttpOnly"
Header edit Set-Cookie "(?i)^(?!.*;\s*httponly\s*(?:[;=]|$))(.*)$" "$1; HttpOnly"
</IfModule>
# TRACEメソッドの無効化(IPA 5-(ix))。httpd.conf(サーバー設定)に記述し、.htaccessでは使えません
TraceEnable off
Apacheは応答ヘッダーを2つの内部表で管理しており、CGI・FastCGI(mod_proxy_fcgi)由来の Set-Cookie は always 側、それ以外の多くは既定(onsuccess)側に入るため、両方の条件で記述します。Webサーバーで一律に付与すると、JavaScriptが読む必要のあるCookie(CSRFトークン、表示設定)まで読めなくなり、画面が動かなくなることがあります。可能な限りアプリケーション側でCookieごとに設定してください。
nginx(リバースプロキシ)
# セッションCookieだけにHttpOnlyを付与(nginx 1.19.3以降)
proxy_cookie_flags PHPSESSID secure httponly samesite=lax;
IIS(ASP.NET)
<system.web>
<httpCookies httpOnlyCookies="true" requireSSL="true" />
</system.web>
Java(Servlet)
<session-config>
<cookie-config>
<http-only>true</http-only>
<secure>true</secure>
</cookie-config>
</session-config>
Next.js(Vercel)
import { cookies } from "next/headers";
(await cookies()).set("session", token, { httpOnly: true, secure: true, sameSite: "lax", path: "/" });
段階的な導入と注意点
- 発行しているCookieの一覧を作り、名前・用途・JavaScriptから読む必要の有無を整理します。
- セッションID・認証トークン・リフレッシュトークンには必ず
HttpOnlyを付けます。 - JavaScriptが読む必要のあるCookieは、機密値を含まないよう設計を見直します(CSRFトークンはセッションIDとは別の値にする等)。
- 確認します。
curl -sSI https://www.city.example.lg.jp/ | grep -i '^set-cookie'
ブラウザの開発者ツールのコンソールで document.cookie を実行し、セッションIDが表示されないことも確認できます。
- あわせて、XSSの根本対策(出力時のエスケープ、CSPの導入)を進めてください。CSPの状態は「Content Security Policy」で確認できます。
HTTPSでのみ送信させる属性は「CookieのSecure属性」、クロスサイト送信の制御は「CookieのSameSite属性」で解説しています。
よくある質問(FAQ)
HttpOnlyを付ければXSS対策は不要ですか?
不要にはなりません。HttpOnlyはCookieの値を盗まれることを防ぐだけで、攻撃スクリプトはCookieを読まずに利用者のブラウザ内で申請や設定変更などの操作を実行できます。出力時のエスケープやCSPによるXSSの根本対策が本筋です。
すべてのCookieにHttpOnlyを付けるべきですか?
スクリプトから参照する必要のないCookieには付けます。CSRF対策のダブルサブミット方式で使うトークン(例:AngularのXSRF-TOKEN)や、文字サイズ・言語切替などJavaScriptが読む表示設定用のCookieはHttpOnlyにできません。
HttpOnlyなしのCookieがあると診断で×になりますか?
×ではなく「△ 要確認」です。公開情報だけではそのCookieをJavaScriptが読む必要があるか判断できないためです。開発者ツールで名前を確認し、セッションIDや認証トークンであれば必ずHttpOnlyを付けてください。
どのCookieがセッションIDか、どう見分ければよいですか?
PHPSESSID・JSESSIONID・ASP.NET_SessionId・connect.sid・laravel_session などはセッションIDで、HttpOnlyが必須です。名前で判断できない場合は、サイトのJavaScriptでdocument.cookieを参照している箇所を検索し、そのCookieを読んでいなければHttpOnlyを付けます。
Google Analyticsの_gaもHttpOnlyにすべきですか?
_gaなどのアクセス解析CookieはJavaScriptが設定・参照するためHttpOnlyにできません。また、JavaScriptで設定されるCookieはSet-Cookieヘッダーのみを観測するこの診断では検出されません。
HttpOnlyが効いているかブラウザで確かめる方法はありますか?
開発者ツールのApplication → CookiesでHttpOnly列にチェックが付いているかを確認します。コンソールでdocument.cookieを実行し、セッションIDが表示されないことでも確認できます。
この項目を含む127項目を、URLを入れるだけで無料診断します。