結論(パスワードをPOSTで送信)
パスワードをPOSTで送信とは、パスワード欄を含むフォームに method="post" を指定し、入力値をURLではなくリクエスト本文で送ることです。HTMLのformは method を指定しないと既定でGETになり、パスワードが ?password=... の形でURLに付加されます。URLはブラウザ履歴やアクセスログに残るため、HTTPSでも防げない漏えい経路になります。OWASP ASVS 5.0.0 V14.2.1も機密データをURLに含めないよう求めています。
この記事のポイント
- formのmethodは指定しないと既定値がGETで、入力値がURLのクエリ文字列に載ります。
- URLはブラウザ履歴、ブックマーク、Webサーバー・プロキシのアクセスログ、画面共有などに残り、HTTPSでは防げません。
- JavaScriptで送信していても、読み込み失敗時などはブラウザの既定動作で送信されるため、HTML側にmethod="post"を明示します。
- サーバー側でも認証処理はPOSTだけを受け付け、過去にGETで送っていた場合はログの削除・マスキングとパスワード変更を行います。
- セキュリティAIチェッカーは、method未指定・GETなどPOST以外のパスワードフォームが1件でもあれば×と判定します。
| 診断項目名 | パスワードをPOSTで送信 |
|---|---|
| 項目ID | forms.password-submit-method |
| 分類 | フォーム・パスワード入力 |
| 重大度・配点の重み | 最重要(critical) 重み 5 |
| 関連する標準・ガイドライン | OWASP ASVS 5.0.0 V14.2.1(機密データはHTTPメッセージ本文またはヘッダーで送り、URLとクエリ文字列に含めない/L1)、RFC 9110 17.9(URIに機密情報を含めることの危険)、OWASP WSTG-CRYP-03(認証情報の送信経路の試験。旧WSTG-ATHN-01を統合)、CWE-598(Use of HTTP Request With Sensitive Query String)、IPA「安全なウェブサイトの作り方」6-(i)-a注記(機密データの送信にGETを使わない) |
パスワードをPOSTで送信とは
パスワードをPOSTで送信とは、パスワード欄を含むHTMLフォームに method="post" を指定し、入力値をURLではなくリクエスト本文で送ることです。
HTMLフォームの送信方法(method 属性)には get と post があり、指定しない場合の既定値はGETです。GETで送信すると、入力値は ?user=...&password=... の形でURLに付加されます。URLはブラウザ履歴、ブックマーク、Webサーバーやプロキシのアクセスログ、解析ツール、画面共有など、さまざまな場所に残ります。
セキュリティAIチェッカーのこの項目は、パスワード欄を含むフォームが method="post" で送信される設定になっているかを確認します。パスワードがURLに載る設計は、暗号化(HTTPS)していても防げない漏えい経路を生むため、重大度criticalとしています。
GETとPOSTの違い
| 観点 | GET | POST |
|---|---|---|
| 入力値の置き場所 | URLのクエリ文字列 | リクエスト本文 |
| ブラウザ履歴・ブックマーク | 残る | 本文は残らない |
| サーバー・プロキシのアクセスログ | 標準設定で記録される | 本文は標準では記録されない |
| Refererヘッダー | ページURLとして送られ得る | 送信値はURLに含まれない |
| HTTPSでの暗号化 | 通信路上は暗号化される | 同左 |
HTMLの仕様上の挙動
<form>のmethodはget/post/dialogのいずれかで、大文字小文字を区別せず、既定値はgetです(MDN)。- 送信ボタン(
<button>、<input type="submit">、<input type="image">)のformmethod属性は、フォームのmethodを上書きします。
なぜパスワードはGETではなくPOSTで送るべきなのか
HTTPSでもURLは端末やサーバーで平文になる
HTTPSはURLを含む通信内容を暗号化しますが、URLは送信元・送信先の端末やサーバーでは平文として扱われます。RFC 9110の17.9節は、URIは共有される前提のものであり、機密情報・個人を識別できる情報を含めるのは賢明でないと述べ、GETフォームのクエリに機密データが入る場合にはPOSTが好まれると説明しています。
OWASP ASVS 5.0.0 V14.2.1(L1)も、機密データはHTTPメッセージ本文またはヘッダーで送り、URLとクエリ文字列に含めないことを求めています。IPA「安全なウェブサイトの作り方」も、機密データの送信にGETを使わないよう注記しています。
パスワードの送信方法についてよくある誤解
- 「JavaScriptでfetchしているからmethodは関係ない」:JavaScriptの読み込み失敗、実行前の素早い送信、エラー発生時などに、ブラウザは既定動作でフォームを送信します。
method未指定ならGETとなり、パスワードがURLに載ります。フレームワークで送信処理を置き換える場合でも、HTML側にmethod="post"と適切なactionを明示しておくことが安全側の設計です。 - 「HTTPSなのでGETでも安全」:上表のとおり、暗号化は通信路だけの保護です。端末の履歴やサーバーのログには残ります。
- 「hiddenで送っている」:hidden項目もGETならURLに載ります。
送信先がHTTPS・同一オリジンかどうかは「認証情報の送信先をHTTPS・同一オリジンへ限定」、パスワード以外のトークンやAPIキーがURLに載っていないかは「機密情報をURL・GETフォームへ含めない」、セッションIDのURL埋め込みは「セッションIDをURLへ含めていない」で確認します。このページは「パスワードフォームの送信方法」に絞って解説します。
パスワードをPOSTで送信の診断基準(セキュリティAIチェッカー)
取得対象
外部診断強化モジュールが、トップページと、Ver2巡回で見つかった同一オリジンの追加ページ(ログイン・管理・アカウント系URLを優先)から最大2ページ、合計最大3ページのHTMLを解析します。追加のリクエストはGETのみで、フォームを実際に送信することはありません。
検出の手順
- HTMLから
<form ...>と、その後に最初に現れる</form>までを1組として抽出し、その内部にtype="password"(引用符なしも可)の<input>を含むものを「パスワードフォーム」とします。 - 各パスワードフォームの開始タグの
method属性を読み取り、値がない場合はHTML仕様の既定値どおりGETとみなします。 - 小文字化した値が
post以外のフォームを「POST以外」と数えます。
判定条件
| 判定 | 条件 | 得点への影響 |
|---|---|---|
| ○ 問題なし(pass) | パスワードフォームがすべて method="post" | 重み5を満点で加算 |
| △ 要確認(warn) | 使用しない | — |
| × 要改善(fail) | 1件でも method 未指定、get、その他の値のパスワードフォームがある | 重み5に対して0点 |
| 対象外(na) | パスワード欄を含むフォームがない | 分母・分子から除外 |
method 未指定を×とするのは、静的HTMLの状態でブラウザが実際にGETで送信する設定だからです。スクリプトによる送信の置き換えは、上記のとおりJavaScript失敗時の保護にならないため考慮しません。根拠欄には「n/m件がPOST以外」のように件数を表示します。
判定の範囲と限界
<form>要素の外にあるパスワード欄(JavaScriptだけで送信するSPA)は、フォームとして数えないため本項目の対象外です。その場合、送信方法は開発者ツールのネットワーク表示で確認してください。- 閉じタグ
</form>のないフォーム、属性値に<や>を含む<form>・<input>タグは抽出できず、対象外になります。 - 送信ボタンの
formmethodによる上書きは評価していません。 - JavaScriptで後から生成されるフォームは取得HTMLに含まれないため、判定できません。
自治体サイトでの判定例
| 状況 | 判定 |
|---|---|
| 公式サイト内にログインフォームがない | 対象外 |
職員向けや事業者向けのログイン画面が <form action="/login.php">(method未指定) | × |
<form action="/login" method="post"> | ○ |
パスワードをGETで送るとどんなリスクがあるか
- アクセスログからの漏えい:Webサーバー、ロードバランサー、WAF、CDN、プロキシは標準でリクエストURLを記録します。ログを閲覧できる運用者、委託先、ログ転送先、ログの漏えい時に第三者が、IDとパスワードの組を入手できます。
- 共用端末の履歴:図書館、公民館、窓口の共用PCで、ブラウザ履歴やアドレスバーの候補から他人のパスワードが見えます。
- Refererによる外部送信:ログイン後のページURLにパスワードが残り、そのページから外部リソースを読み込むと、Referrer-Policyの設定次第では外部サイトへURLが送られます。現行の主要ブラウザの既定(
strict-origin-when-cross-origin)ではクロスオリジンにはオリジンだけが送られますが、ポリシーを緩めている場合は全URLが渡ります。 - 画面共有・スクリーンショット:オンライン会議や操作マニュアル作成時にアドレスバーが映り込みます。
いずれも暗号化では防げないため、被害は認証情報の漏えいとなりすましに直結します。
パスワードをPOSTで送信する設定方法(HTML・PHP・Next.js・Apache)
1. フォームに method="post" を明示する
<form action="/login" method="post" autocomplete="on">
<label for="uid">利用者ID</label>
<input id="uid" name="username" autocomplete="username" required>
<label for="pw">パスワード</label>
<input id="pw" type="password" name="password"
autocomplete="current-password" required>
<input type="hidden" name="csrf_token" value="(サーバー生成値)">
<button type="submit">ログイン</button>
</form>
2. サーバー側でもGETを拒否する
HTMLを直しても、古いリンクやブックマークからGETで届く場合があります。認証処理はPOSTだけを受け付けます。
<?php
// login.php:POST以外は405
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
header('Allow: POST');
http_response_code(405);
exit;
}
$user = $_POST['username'] ?? '';
$pass = $_POST['password'] ?? '';
// Next.js App Router:app/api/login/route.ts
export async function POST(request: Request) {
const form = await request.formData();
// 認証処理
return new Response(null, { status: 204 });
}
// GETをexportしなければ、GETは405になります
3. 既存ログからパスワードを消す
過去にGETで送信していた場合、アクセスログにパスワードが記録されています。
- ログの保管場所(Webサーバー、WAF、CDN、ログ集約基盤、バックアップ)を洗い出します。
password=などを含む行を確認し、保存規程に従って削除またはマスキングします。- 影響を受けた利用者にパスワード変更を依頼します。
Apacheでは、該当パラメータを含むURLをログから除外する例として次の設定があります(暫定措置。根本対策はPOST化です)。
# SetEnvIfのRequest_URIはクエリ文字列を含まないため、式でQUERY_STRINGを判定
SetEnvIfExpr "%{QUERY_STRING} =~ /(^|&)(password|passwd|pwd)=/i" nolog_secret
CustomLog logs/access_log combined env=!nolog_secret
4. Referrer-Policyを設定する
URLに機密情報が残らないことが前提ですが、多層防御として Referrer-Policy: strict-origin-when-cross-origin(またはより厳しい same-origin、no-referrer)を設定します。
修正後の確認方法
# パスワードフォームのmethodを確認
curl -s https://www.example.lg.jp/login/ \
| tr '\n' ' ' | grep -oiE '<form[^>]*>'
# 認証エンドポイントがGETを拒否するか
curl -s -o /dev/null -w "%{http_code}\n" "https://www.example.lg.jp/login?username=a&password=b"
ブラウザの開発者ツール(ネットワーク)でログインし、リクエストのメソッドがPOSTで、URLに入力値がないことを確認します。修正後はセキュリティAIチェッカーで再診断し、この項目が○になることを確認します。
サイトを壊さないための注意点
method="post"にすると、サーバー側がGETの$_GETだけを読んでいる場合にログインできなくなります。HTMLとサーバー処理を同時に修正してください。- POSTにするとCSRF対策(トークン、SameSite属性)が必要になります。「POSTフォームのCSRF対策兆候」、「CookieのSameSite属性」もあわせて確認します。
- POST後の画面をそのまま返すと、再読み込みで二重送信の確認ダイアログが出ます。ログイン成功後は303リダイレクトでGETの画面へ移す「PRGパターン」が一般的です。
- パッケージ製品の場合、改修はベンダー対応となります。暫定策としてWAFやリバースプロキシで該当URLへのGETを拒否できるか検討してください。
よくある質問(FAQ)
formのmethodを指定しないとどうなりますか?
HTMLの仕様上、methodの既定値はGETです。そのため、method未指定のログインフォームはパスワードを ?user=...&password=... の形でURLに付けて送信します。
HTTPSならGETでパスワードを送っても安全ではありませんか?
安全ではありません。HTTPSは通信路上を暗号化しますが、URLは端末やサーバーでは平文として扱われ、ブラウザ履歴やアクセスログに残ります。暗号化は通信路だけの保護です。
JavaScriptのfetchで送信している場合もmethod="post"は必要ですか?
必要です。JavaScriptの読み込み失敗、実行前の素早い送信、エラー発生時などに、ブラウザは既定動作でフォームを送信します。method未指定ならGETになるため、HTML側にmethod="post"と適切なactionを明示しておくのが安全です。
過去にGETでパスワードを送っていた場合はどうすればよいですか?
Webサーバー、WAF、CDN、ログ集約基盤、バックアップなどのログ保管場所を洗い出し、password= などを含む行を保存規程に従って削除またはマスキングします。影響を受けた利用者にはパスワード変更を依頼します。
POSTに変えるときに注意することは?
サーバー側がGETの値だけを読んでいるとログインできなくなるため、HTMLとサーバー処理を同時に修正します。あわせてCSRF対策(トークン、SameSite属性)と、ログイン成功後に303リダイレクトでGET画面へ移すPRGパターンを検討します。
パスワードをPOSTで送信しているかは、セキュリティAIチェッカーでどう判定されますか?
パスワード欄を含むフォームがすべてmethod="post"なら「○ 問題なし」、method未指定・get・その他の値が1件でもあれば「× 要改善」(重み5に対して0点)、パスワード欄を含むフォームがなければ「対象外」です。
この項目を含む127項目を、URLを入れるだけで無料診断します。
参考資料
- OWASP ASVS 5.0.0 V14 Data Protection(14.2.1)
- RFC 9110 HTTP Semantics, 17.9 Disclosure of Sensitive Information in URIs
- MDN form element(method / formmethod)
- OWASP WSTG-CRYP-03 Sensitive Information Sent via Unencrypted Channels
- CWE-598 Use of HTTP Request With Sensitive Query String
- IPA「安全なウェブサイトの作り方」(PDF)
- MDN Referrer-Policy