結論(セッションIDをURLへ含めていない)
セッションIDをURLへ含めていないとは、ログイン状態を示すセッションIDを ?PHPSESSID=… や ;jsessionid=… のようにURLへ入れていない状態です。セッションIDは、Secure・HttpOnly・SameSite付きのCookieだけでやり取りします。URLに入ったIDはブラウザ履歴、アクセスログ、Referer、URLの共有を通じて第三者に渡り、なりすましやセッション固定攻撃に使われます。IPA「安全なウェブサイトの作り方」とOWASP ASVS 5.0.0 V14.2.1が求める基本対策です。
この記事のポイント
- セッションIDは「ログイン済みの本人」を示す合い鍵で、URLに入ると履歴・ログ・Referer・共有URLから漏れます。
- PHPの透過的セッションID、Javaの;jsessionid=、ASP.NETのcookielessセッションが典型的な原因です。
- PHPはsession.use_only_cookies=1、Javaはtracking-mode COOKIE、ASP.NETはcookieless="UseCookies"でCookie専用にします。
- セキュリティAIチェッカーは入力URL・リダイレクト経路・ページ内リンクなどを調べ、1件でもIDを含めば×と判定します。
- 未ログイン状態での巡回のため、ログイン後の画面は手動確認が必要です。
| 診断項目名 | セッションIDをURLへ含めていない |
|---|---|
| 項目ID | session.id-in-url |
| 分類 | Cookie・セッション管理 |
| 重大度・配点の重み | 重要(high) 重み 4 |
| 関連する標準・ガイドライン | OWASP ASVS 5.0.0 V14.2.1(L1:機密データはHTTPメッセージ本文またはヘッダーで送り、URL・クエリ文字列にAPIキーやセッショントークンを含めない)、IPA「安全なウェブサイトの作り方」1.4 セッション管理の不備 根本的解決 4-(ii)(セッションIDをURLパラメータに格納しない)、OWASP WSTG-SESS-04(Testing for Exposed Session Variables)、OWASP Session Management Cheat Sheet、CWE-598(Use of HTTP Request With Sensitive Query String) |
セッションIDをURLへ含めていない状態とは
セッションIDをURLへ含めていないとは、ログイン状態を識別するセッションIDを、?PHPSESSID=… や ;jsessionid=… のようにURLの中に入れず、Cookieだけでやり取りしている状態のことです。
セッションIDは「ログイン済みの本人である」ことを示す合い鍵です。URLに入っていると、ブラウザ履歴、ブックマーク、アクセスログ、プロキシのログ、外部サイトへの Referer、SNSやメールでのURL共有などを通じて第三者に渡り、なりすましに使われます。IPAとOWASPはいずれも、セッションIDはCookieでやり取りし、URLに入れないことを求めています。
セキュリティAIチェッカーのこの項目は、診断対象のURL、リダイレクトの途中経路、巡回したページのURL、ページ内のリンクやフォーム送信先から抽出した同一オリジンのURLに、セッションIDと判断できる値が含まれていないかを確認します。
URLにセッションIDが入る典型パターン
| 方式 | URLの例 | 発生原因 |
|---|---|---|
| PHPの透過的セッションID | /form.php?PHPSESSID=… | session.use_trans_sid = 1 かつ session.use_only_cookies = 0、またはCookie拒否端末向けの互換設定 |
| Java(Servlet)のURLリライト | /app/list.do;jsessionid=… | Cookieが使えない初回アクセス時に encodeURL() がパスへ付与 |
| ASP.NETのcookielessセッション | /(S(lit3py55t21z5v55vlm25s55))/orderform.aspx | web.config の sessionState cookieless="true" |
| 独自実装 | ?sid=…、?session_id=… | フィーチャーフォン対応の名残、Cookieを使わない設計 |
PHPのマニュアルは、session.use_only_cookies の既定値が1(Cookieのみ)であり、URLにセッションIDを渡す攻撃を防ぐと説明しています。また session.use_trans_sid は既定で無効で、PHP 8.4ではこれを有効にすることが非推奨になりました。Microsoftの文書も、cookielessセッションのURLが検索エンジンやメールで共有されると、複数のブラウザで同じセッションが使われうると注意しています。
なぜセッションIDはURLではなくCookieで扱うべきなのか
Cookieは属性で守れ、履歴やログに残らない
Cookieは、次の属性で保護できます。
| 属性 | 効果 | 関連項目 |
|---|---|---|
Secure | HTTPSのみで送信 | 「CookieのSecure属性」 |
HttpOnly | JavaScriptから読めない | 「CookieのHttpOnly属性」 |
SameSite | 他サイト起点のリクエストで送らない | 「CookieのSameSite属性」 |
また、URLのように履歴・ログ・Refererへ自動的に残ることもありません。OWASP Session Management Cheat Sheetは、セッションIDの受け渡しをCookieに限定し、URLパラメータなど別経路で送られてきたIDを受け付けないことを、セッション固定攻撃への防御としても推奨しています。
標準・ガイドラインの要求
| 出典 | 要求 |
|---|---|
| OWASP ASVS 5.0.0 V14.2.1(L1) | 機密データはHTTPメッセージ本文またはヘッダーで送り、URL・クエリ文字列にAPIキーやセッショントークンを含めない |
| IPA「安全なウェブサイトの作り方」1.4 根本的解決 4-(ii) | セッションIDをURLパラメータに格納しない |
| OWASP WSTG-SESS-04 | 露出したセッション変数の検査 |
| CWE-598 | 機微なクエリ文字列を含むHTTPリクエストの使用(Use of HTTP Request With Sensitive Query String) |
セッションIDとURLについてよくある誤解
- 「HTTPSならURLも暗号化されるから安全」:通信経路上では暗号化されますが、サーバーのアクセスログ、ブラウザ履歴、Referer、利用者による貼り付け共有では平文のまま残ります。
- 「ログイン前だけだから問題ない」:ログイン前に発行されたIDがログイン後もそのまま使われる実装では、URLで知られたIDを使ったセッション固定攻撃が成立します。ログイン成功時のID再発行(IPA 4-(iv)-a)とあわせて確認が必要です。
- 「sidという名前は全部セッションID」:
sidはサイトID、セクションIDなど別の意味で使われることも多い名前です。本診断は値の形も見て判断します。
セッションIDをURLへ含めていないの診断基準(セキュリティAIチェッカー)
取得方法
次のURLを候補として集めます(3・4は同一オリジンのURLに限定し、外部サイトへのリンクは対象外。1のリダイレクト経路はオリジンを問わず含みます)。
- 入力されたURLと最終到達URL、リダイレクトの途中URL。
- 追加取得した下層ページ(最大2件)の最終URL。
- トップページと下層ページのHTMLに含まれる
<a>・<link>・<script>・<img>・<iframe>のhref/src、<form action>、JavaScript内のlocation =・fetch()・axios.get/post()のURL。 - V2診断の巡回ページ候補とAPI候補。
セッションIDを含むURLの判定条件
各URLについて次のいずれかに該当すれば「セッションIDを含むURL」と数えます。値そのものは画面・ログへ表示しません。
| 種別 | 条件 |
|---|---|
| Java系パスパラメータ | ;jsessionid= の後に値がある |
| ASP.NET cookieless | パスに /(S(英数字16文字以上))/ または /(F(…))/ の形がある |
| 既知のセッション名 | クエリ名が PHPSESSID、JSESSIONID、ASPSESSIONID〜、ASP.NET_SessionId(大文字小文字区別なし)で、値が空でない |
| 汎用名 | クエリ名が sid、session_id、sessionid(大文字小文字区別なし)で、値が英数字と + / = , . _ ~ : - のみからなる16文字以上で、数字を1文字以上含むトークン形式 |
判定条件
| 判定 | 条件 | 得点への影響 |
|---|---|---|
| ○ 問題なし(pass) | 候補URLのいずれにも該当しない | 重み4 × 1.00 |
| × 要改善(fail) | 1件でも該当する | 重み4 × 0 |
| 対象外(na) | なし(入力URLは常に存在するため判定可能) | — |
- 汎用名に16文字以上の条件を付けているのは、
?sid=12のようなサイト・カテゴリ番号を誤ってセッションIDと判定しないためです。数字を含まない値(例:?sid=shisetsu-yoyaku-annaiのような英字だけの識別名)も該当しません。PHPのセッションIDは22〜256文字(既定32文字)、ASP.NETのcookieless IDは24文字であり、実際のセッションIDはこの条件を満たします。 - 本診断は未ログイン状態での巡回です。ログイン後の画面だけでURLにIDを付ける実装は検出できないため、ログイン機能を持つシステムは手動確認が必要です。
- 機密パラメータ全般(パスワード、アクセストークン、APIキー等)のURL露出は、別項目「機密情報をURL・GETフォームへ含めない」で判定します。
- 証拠欄には、該当したURLの件数(値は非表示)または確認した候補URLの件数を表示します。
自治体サイトでの判定例
| 状況 | 判定 |
|---|---|
旧来の施設予約システムへのリンクが /yoyaku/top.php?PHPSESSID=… の形でトップページに埋め込まれている | × |
電子申請システムの入口が Java製で、初回アクセスのリダイレクト先が /shinsei/index.jsp;jsessionid=… | × |
お知らせ一覧のURLが /news/list.php?sid=3(3はカテゴリ番号) | ○(トークン形式ではない) |
| CMSのみで構成され、Cookieでセッション管理 | ○ |
セッションIDがURLに含まれているとどんなリスクがあるか
- Refererによる外部流出:URLにIDを含むページから外部サイトへのリンクをクリックすると、
RefererヘッダーにID付きURLが入り、外部サイトのログに残る可能性があります(Referrer-Policyの既定値strict-origin-when-cross-originではパスとクエリは送られませんが、古い設定やポリシー変更で送られる場合があります)。IPAもRefererによる送信を理由に挙げています。 - 共有・掲載による乗っ取り:利用者が「このページを見てください」とURLをメールやSNSに貼ると、受け取った人がそのままログイン状態になる場合があります。
- セッション固定攻撃:攻撃者が自分で取得したセッションID付きURLを被害者に踏ませ、被害者がログインした後に同じIDで操作する攻撃です。URLでIDを受け付ける実装で成立しやすくなります。
- ログからの漏えい:アクセスログ、プロキシ、アクセス解析ツール、検索エンジンのクロールにID付きURLが残り、運用者や委託先を含む広い範囲から参照可能になります。
セッションIDをURLから外す設定方法(PHP・Java・ASP.NET・Apache)
PHP(php.ini / .user.ini)
session.use_only_cookies = 1
session.use_trans_sid = 0
session.use_strict_mode = 1 ; 未知のIDを受け付けない
session.cookie_secure = 1
session.cookie_httponly = 1
session.cookie_samesite = "Lax"
ログイン成功時には session_regenerate_id(true); を呼び、IDを再発行します。共有ホスティングでは .htaccess の php_value ではなく .user.ini に書いてください(mod_php以外では php_value が500エラーの原因になります)。
Java(Servlet 3.0以降の web.xml)
<session-config>
<cookie-config>
<http-only>true</http-only>
<secure>true</secure>
</cookie-config>
<tracking-mode>COOKIE</tracking-mode>
</session-config>
tracking-mode を COOKIE のみにすると、;jsessionid= のURLリライトが行われなくなります。
ASP.NET(web.config)
<system.web>
<sessionState cookieless="UseCookies" regenerateExpiredSessionId="true" />
<authentication mode="Forms">
<forms cookieless="UseCookies" requireSSL="true" />
</authentication>
<httpCookies httpOnlyCookies="true" requireSSL="true" />
</system.web>
Webサーバーでの暫定対処(Apache)
アプリを直ちに修正できない場合、ID付きURLへのGETアクセスを、PHPSESSID だけを除いた(他のパラメータは残した)URLへリダイレクトする方法があります。ただしCookieを受け付けない端末ではログインできなくなるため、影響範囲を確認してから適用してください。
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_METHOD} =GET
RewriteCond %{QUERY_STRING} ^(.*&)?PHPSESSID=[^&]*&?(.*)$ [NC]
RewriteRule ^ %{REQUEST_URI}?%1%2 [R=302,L,NE]
</IfModule>
段階的な手順
| 手順 | 内容 |
|---|---|
| 1 | 本診断の証拠でfailになったURLの出どころ(どのページのリンクか、どのシステムか)を特定します |
| 2 | 委託先システムであれば、Cookie専用化の設定変更を依頼します |
| 3 | HTMLテンプレートやCMSの固定リンクにID付きURLが貼り込まれていないか検索し、IDを除いたURLへ差し替えます |
| 4 | ログイン後の画面でも、アドレスバー・リンク・フォームのaction・リダイレクト先にIDが出ないことを確認します |
| 5 | 過去にID付きURLが公開されていた場合は、検索エンジンのキャッシュやアクセスログの取り扱いを確認します |
設定後の確認方法
# トップページ内のリンクにセッションIDらしきパラメータがないか
curl -s https://www.example.lg.jp/ | grep -ioE '(phpsessid|jsessionid|aspsessionid|session_?id)=[^"&<]*' | head
# リダイレクト経路のLocationを確認
curl -s -o /dev/null -D - https://www.example.lg.jp/shinsei/ | grep -i '^location'
# Cookieでセッションが発行されているか
curl -s -o /dev/null -D - https://www.example.lg.jp/yoyaku/ | grep -i '^set-cookie'
サイトを壊さないための注意点
- Cookie専用化により、Cookieを無効にした端末や一部の古い携帯端末ではログインできなくなります。利用者向けの案内(Cookieを有効にする手順)を用意してください。
session.use_strict_modeの有効化は、セッション固定攻撃対策として推奨されますが、独自のセッションハンドラを使う実装では動作確認が必要です。
よくある質問(FAQ)
HTTPSで通信していれば、URLにセッションIDがあっても安全ですか?
安全ではありません。通信経路上では暗号化されますが、サーバーのアクセスログ、ブラウザ履歴、Referer、利用者による貼り付け共有では平文のまま残ります。
ログイン前のページだけURLにIDが付くのは問題ですか?
問題になり得ます。ログイン前に発行されたIDがログイン後もそのまま使われる実装では、URLで知られたIDを使ったセッション固定攻撃が成立します。ログイン成功時のID再発行(IPA 4-(iv)-a)とあわせて確認が必要です。
URLの ?sid= はすべてセッションIDとして×になりますか?
なりません。sidはサイトIDやセクションIDの意味でも使われるため、値が16文字以上で数字を含むトークン形式の場合だけ該当とします。?sid=3 のようなカテゴリ番号や、英字だけの識別名は○です。
PHPでURLにPHPSESSIDが付かないようにするには?
php.iniまたは.user.iniでsession.use_only_cookies = 1、session.use_trans_sid = 0にし、session.use_strict_mode = 1で未知のIDを受け付けないようにします。ログイン成功時にはsession_regenerate_id(true)でIDを再発行します。
Cookie専用にすると困る利用者はいますか?
Cookieを無効にした端末や一部の古い携帯端末ではログインできなくなります。Cookieを有効にする手順など、利用者向けの案内を用意してください。
パスワードやアクセストークンがURLに入っている場合も、セッションIDをURLへ含めていないかの項目で判定されますか?
この項目はセッションIDに絞っています。パスワード、アクセストークン、APIキーなど機密パラメータ全般のURL露出は「機密情報をURL・GETフォームへ含めない」で判定します。
この項目を含む127項目を、URLを入れるだけで無料診断します。