結論(機密情報をURL・GETフォームへ含めない)
機密情報をURL・GETフォームへ含めないとは、パスワード、アクセストークン、APIキー、セッションID、カード番号のような機密情報を、URLのクエリ文字列やGET送信のフォーム項目に載せないことです。URLはブラウザ履歴、サーバーやCDNのアクセスログ、Refererヘッダー、画面共有などに複製されるため、HTTPSで通信していても漏えいします。OWASP ASVS 5.0.0 V14.2.1は、機密データをHTTPメッセージ本文かヘッダーで送るよう求めています。
この記事のポイント
- URLは共有される前提のもので、履歴・アクセスログ・解析タグ・Referer・スクリーンショットなど多くの場所に残ります。
- HTTPSは通信路上を暗号化するだけで、端末やサーバーで記録されるURLは平文です。
- 診断ではpassword・secret・access_token・api_key・phpsessid・cvvなど代表的な名前との完全一致で検出し、値は収集・表示しません。
- パスワードはPOST本文、セッションIDはCookie、APIの認証情報はAuthorizationヘッダーやサーバー側中継で送ります。
- URLに載せていたAPIキーやトークンは漏えい済みとみなし、再発行と旧キーの無効化を行います。
| 診断項目名 | 機密情報をURL・GETフォームへ含めない |
|---|---|
| 項目ID | data.sensitive-url-parameters |
| 分類 | フォーム・パスワード入力 |
| 重大度・配点の重み | 最重要(critical) 重み 5 |
| 関連する標準・ガイドライン | OWASP ASVS 5.0.0 V14.2.1(機密データはHTTPメッセージ本文またはヘッダーで送り、URLとクエリ文字列にAPIキーやセッショントークン等を含めない/L1)、RFC 9110 17.9(Disclosure of Sensitive Information in URIs)、CWE-598(Use of HTTP Request With Sensitive Query String)、OWASP WSTG-SESS-04(Exposed Session Variables:GETによるセッションID・認証情報の送信を確認)、IPA「安全なウェブサイトの作り方」1.4(セッションIDをURLパラメータに格納しない) |
機密情報をURL・GETフォームへ含めないとは
機密情報をURL・GETフォームへ含めないとは、パスワード、アクセストークン、APIキー、セッションID、カード番号のような機密情報を、URLのクエリ文字列(? 以降)や、GETで送信するフォームの項目に載せないことです。
URLは「共有されるもの」として設計されており、ブラウザ履歴、ブックマーク、サーバーやCDNのアクセスログ、解析ツール、Refererヘッダー、メールやチャットへの貼り付けなど、多くの場所に複製されます。機密情報をURLのクエリに含めると、HTTPSで通信していても、これらの複製先から漏えいします。
セキュリティAIチェッカーのこの項目は、診断で巡回・発見したURLと、GET送信のフォームの項目名に、代表的な機密情報の名前が含まれていないかを確認します。値は収集・表示しません。
URLが残る場所
| 場所 | 内容 |
|---|---|
| ブラウザ | 履歴、アドレスバーの候補、ブックマーク、同期されたクラウド履歴 |
| サーバー側 | Webサーバー、リバースプロキシ、WAF、CDN、ロードバランサーのアクセスログ |
| 第三者 | アクセス解析タグ、広告タグ、外部埋め込み(Refererとして) |
| 人 | 画面共有、スクリーンショット、問い合わせ時のURL貼り付け |
なぜ機密情報をURLに含めてはいけないのか
標準の考え方
RFC 9110の17.9節は、URIは機密リソースを指す場合でも保護の対象ではなく共有されるものであり、機密情報・個人識別情報を含めるのは賢明でないと述べています。GETフォームのクエリに機密データが入る場合、本文で送るPOSTが好まれるとも説明しています。
OWASP ASVS 5.0.0 V14.2.1(L1)は、機密データをHTTPメッセージ本文かヘッダーで送り、URLとクエリ文字列にAPIキーやセッショントークンなどを含めないことを求めています。IPA「安全なウェブサイトの作り方」1.4も、セッションIDをURLパラメータに格納しないよう求めています。
Refererと現在のブラウザ既定値
主要ブラウザの既定のReferrer-Policyは strict-origin-when-cross-origin で、別オリジンへのリクエストにはオリジン(https://example.lg.jp/)だけが送られ、パスやクエリは送られません(MDN)。ただし、サイトが unsafe-url や no-referrer-when-downgrade を明示している場合、または同一オリジン内の通信では、クエリを含む完全なURLが送られます。既定値に頼らず、そもそもURLに機密情報を載せないことが基本です。
URLの機密情報についてよくある誤解
- 「HTTPSならURLも暗号化されるので安全」:通信路上では暗号化されますが、端末やサーバーで記録されるURLは平文です。
- 「ワンタイムだから問題ない」:パスワード再設定リンクのように、URLにトークンを含めざるを得ない用途もあります。その場合は短い有効期限、1回限りの使用、使用後の無効化、ページの
Referrer-Policy: no-referrerなどで露出を抑えます。本項目はtoken単体の名前を対象外とし、access_tokenなどの認証トークン名に絞っています。
パスワード欄を含むフォームの送信方法は「パスワードをPOSTで送信」、セッションIDのURL埋め込みは「セッションIDをURLへ含めていない」、Refererの送り方は「Referrer-Policy」で確認します。このページは「URLとGETフォームの項目名に機密情報の名前がないか」に絞って解説します。
機密情報をURL・GETフォームへ含めないの診断基準(セキュリティAIチェッカー)
取得対象
外部診断強化モジュールが、次のURL候補とHTMLを使います。HTMLから抽出するURLと巡回結果は同一オリジンに限ります(入力URLとリダイレクト経路のURLは、別オリジンであっても対象です)。
- 入力URL、最終URL、リダイレクト経路のURL
- トップページと追加ページ(トップページを含め最大3ページ)の最終URL
- それらのHTML内の
<a>・<link>・<script>・<img>・<iframe>のhref/src、<form>のaction、location=・fetch(・axios.get/post(に書かれたURL - Ver2巡回で確認したページとAPI候補
機密情報とみなす名前
機密情報とみなすパラメータ名・項目名は、次の名前と大文字小文字を区別せず完全一致するものです。
password、passwd、pwd、secret、access_token/accesstoken、refresh_token/refreshtoken、id_token/idtoken、api_key/api-key/apikey、authorization、session_id/sessionid、phpsessid、jsessionid、aspsessionid、cvv、card_number/cardnumber
検出の手順
- 各URL候補のクエリパラメータ名を調べ、上記に一致する名前の種類数を数えます。
- 各ページの
<form ...>〜最初の</form>の組(閉じタグのないフォームは対象外)のうち、methodがpostでないもの(未指定はGET)について、内部の<input>・<select>・<textarea>のname属性が上記に一致する件数を数えます。
判定条件
| 判定 | 条件 | 得点への影響 |
|---|---|---|
| ○ 問題なし(pass) | URLにもGETフォームにも該当名がない | 重み5を満点で加算 |
| △ 要確認(warn) | 使用しない | — |
| × 要改善(fail) | URLの該当パラメータ名、またはGETフォームの該当項目が1件以上ある | 重み5に対して0点 |
| 対象外(na) | 使用しない(URLは常に存在するため必ず判定) | — |
根拠には「URLに機密名のパラメータがn種類、GETフォームに機密名の項目がm件」と件数だけを表示し、値は表示しません。
判定の範囲と限界
- 名前の完全一致で判定するため、
pw、pass、key、token、mailなどの短い名前や独自の名前は対象外です(誤検知を避けるため)。パスワード欄を含むGETフォームは、名前に関係なく「パスワードをPOSTで送信」で別途検出されます。 - 調べるのはクエリパラメータ名(
?以降)だけです。/menu.do;jsessionid=...のようにパスへ埋め込む形式は本項目では数えず、「セッションIDをURLへ含めていない」が検出します。 - 認証後の画面、JavaScriptが実行時に生成するURL、メール本文のリンクは確認できません。
自治体サイトでの判定例
| 状況 | 判定 |
|---|---|
公式サイトのページURLが /soshiki/kikaku/12345.html 形式で、検索フォームは q だけ | ○ |
地図アプリの埋め込みURLに ?api_key=... が付いた同一オリジンの中継URLがある | × |
旧システムへのリンクに ?PHPSESSID=... が付いている | ×(session.id-in-url も不合格) |
/app/menu.do;jsessionid=... の形式だけ | 本項目は○のまま、session.id-in-url が不合格 |
機密情報をURLに含めるとどんなリスクがあるか
- アクセスログ経由の漏えい:ログを閲覧できる運用者・委託先、ログ転送先のクラウドサービス、ログファイルの誤公開から、APIキーやトークンが第三者に渡ります。APIキーが漏れると、利用料金の不正発生や、APIで扱うデータの取得・改ざんにつながります。
- セッションハイジャック:URLのセッションIDが他人に渡ると、ログイン状態を乗っ取られます。IPAの「安全なウェブサイトの作り方」は、URLパラメータのセッションIDがRefererで外部サイトへ送られる危険を説明しています。
- 共有による拡散:住民が問い合わせでURLを貼り付けた、職員がマニュアルにスクリーンショットを載せた、といった通常の行為で機密情報が広がります。
- 検索エンジンへの登録:リンクとして公開ページに書かれたURLは、検索エンジンにクロールされ、キャッシュや検索結果に残ることがあります。
機密情報をURLに含めないための対策方法(PHP・Apache・nginx)
1. 送り方を変える
| 情報 | 推奨される送り方 |
|---|---|
| パスワード | POSTの本文(forms.password-submit-method) |
| セッションID | Secure・HttpOnly・SameSite 属性付きCookie |
| APIの認証情報 | Authorization ヘッダー、またはサーバー側で保持し中継 |
| 地図・翻訳など外部APIのキー | サーバー側の中継(プロキシ)でヘッダーに付与し、ブラウザに渡さない。ブラウザで使う必要があるキーは提供元のリファラー・ドメイン制限を必ず設定 |
<?php
// APIキーをサーバー側だけで保持し、ヘッダーで送信する中継の例
// MAP_API_KEY は .env を読み込むライブラリやサーバー設定(SetEnv 等)で環境変数に設定しておく
$key = getenv('MAP_API_KEY');
$ch = curl_init('https://api.example.com/v1/geocode');
curl_setopt_array($ch, [
CURLOPT_HTTPHEADER => ['x-api-key: ' . $key, 'Content-Type: application/json'],
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode(['q' => $_POST['q'] ?? '']),
CURLOPT_RETURNTRANSFER => true,
]);
echo curl_exec($ch);
getenv() は .env ファイルを自動では読み込みません。.env を使う場合は読み込みの仕組みを用意したうえで、ファイルは公開ディレクトリの外に置くか、.htaccess で <Files ".env"> Require all denied </Files> として直接取得を拒否します。
2. セッションIDをURLへ出さない設定
; PHP(php.ini または .user.ini)
session.use_only_cookies = 1
session.use_trans_sid = 0
session.cookie_secure = 1
session.cookie_httponly = 1
session.cookie_samesite = "Lax"
session.use_only_cookies = 1 と session.use_trans_sid = 0 はPHPの既定値で、PHP 8.4以降は逆の設定(前者の無効化、後者の有効化)が非推奨です。
Java(Tomcat等)では web.xml の <session-config><tracking-mode>COOKIE</tracking-mode></session-config> でURL書き換えを無効化できます。
3. Referrer-Policyを設定する
<IfModule mod_headers.c>
Header always set Referrer-Policy "strict-origin-when-cross-origin"
</IfModule>
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
パスワード再設定ページなど、URLにトークンを含むページは no-referrer にします。
4. 漏えい済みの情報を無効化する
URLに載せていたAPIキーやトークンは、すでにログ等に残っていると考え、キーの再発行(ローテーション)と旧キーの無効化を行います。セッションIDの場合は全セッションを破棄し、再ログインを求めます。
修正後の確認方法
# 公開HTMLから機密名パラメータを探す
curl -s https://www.example.lg.jp/ | grep -oiE '[?&;](password|passwd|pwd|secret|access_token|api_?key|apikey|phpsessid|jsessionid|session_?id)=' | sort | uniq -c
# アクセスログを確認(サーバー上)
grep -iE '[?&](password|api_?key|access_token)=' /var/log/httpd/access_log | wc -l
修正後はセキュリティAIチェッカーで再診断し、この項目が○になることを確認します。
サイトを壊さないための注意点
- APIキーをURLから外すと、外部サービス側がクエリでしかキーを受け付けない場合に動作しなくなります。提供元の仕様(ヘッダー認証の可否)を先に確認してください。
session.use_trans_sid = 0にすると、Cookieを無効にしている利用者はセッションを維持できなくなります。現在の主要ブラウザ環境ではCookieが前提であり、案内文の用意で対応するのが一般的です。- キーのローテーションは、新キーの設定→動作確認→旧キー無効化の順に行い、停止時間を作らないようにします。
よくある質問(FAQ)
HTTPSならURLに機密情報を含めても安全ですか?
安全ではありません。URLは通信路上では暗号化されますが、ブラウザ履歴、Webサーバー・CDNのアクセスログ、解析ツールなどには平文で記録されます。
URLやGETフォームのどのパラメータ名が機密情報として検出されますか?
password、passwd、pwd、secret、access_token、refresh_token、id_token、api_key、authorization、session_id、phpsessid、jsessionid、aspsessionid、cvv、card_number などと、大文字小文字を区別せず完全一致する名前です。pw、pass、key、tokenのような短い名前は誤検知を避けるため対象外です。
パスワード再設定リンクのようにURLにトークンが必要な場合は?
用途上やむを得ない場合は、短い有効期限、1回限りの使用、使用後の無効化、ページの Referrer-Policy: no-referrer などで露出を抑えます。本項目は token 単体の名前を対象外とし、access_token などの認証トークン名に絞っています。
地図などの外部APIキーはどう扱えばよいですか?
サーバー側の中継(プロキシ)でヘッダーに付与し、ブラウザに渡さない方法が基本です。ブラウザで使う必要があるキーは、提供元のリファラー・ドメイン制限を必ず設定します。
URLに載せていたAPIキーはどうすればよいですか?
すでにログ等に残っていると考え、キーの再発行(ローテーション)と旧キーの無効化を行います。新キーの設定、動作確認、旧キー無効化の順に進めると停止時間を作らずに済みます。
機密情報をURL・GETフォームへ含めていないかは、セキュリティAIチェッカーでどう判定されますか?
巡回・発見したURLのクエリパラメータ名、またはGET送信フォームの項目名に機密名が1件でもあれば「× 要改善」(重み5に対して0点)、なければ「○ 問題なし」です。URLは常に存在するため、対象外にはなりません。
この項目を含む127項目を、URLを入れるだけで無料診断します。