運用がデータベースのパスワードを同僚へ渡すとき、いちばん楽な書き方はクリックできるリンクです。厄介なのは、そのリンクが一度開かれると、ブラウザ、リバースプロキシ、オリジン、いくつものログを通ることです。本当に制御すべきは「暗号が安全そうか」ではなく、復号鍵がどの層に出るかです。
鍵を ?key= の後ろに書くと HTTP リクエストの一部になり、ほぼ確実に access log に入ります。鍵を # の後ろに書くと、ブラウザは送信前にそれを剥ぎます。某製品の約束ではなく、URI 仕様の fragment の扱いです。本篇が答えるのは、鍵をなぜ井号の後ろに置かねばならないか、そして「サーバーがその一段を受け取っていない」ことを自分でどう見るかです。
鍵をクエリに置くと、ログに何が残るか
クエリ(? から # の前まで)はリクエスト対象です。ブラウザが /s.html?id=abc&key=MYSECRET を取るとき、経路とクエリは回線に乗ります。オリジンも、手前の Nginx、CDN、WAF、APM も見ます。既定の access log は request URI を含むことが多く、key=MYSECRET はステータスと所要時間と同じ行に書かれます。
この一行はあとから消しにくい。ログはディスクへ回り、バックアップ、SIEM、「500 をコピー」するサポート調査へ入ります。エラートラッキングはリクエスト本体と URL を好みます。復号が一度失敗すれば、鍵付きアドレスがクラッシュ報告に入り得ます。法域と下請け運用は「ログは見ません」を監査できない文に変えます。確かめられるのはプロトコルであり、相手のサーバー室の内部規則ではありません。
もっと隠れたコピーもあります。ブラウザ自身の履歴、共有した「完全 URL」のスクリーンショット、監視スクリプトが location.href を丸ごと上げること。クエリは少なくともサーバー側に先に落ちます。fragment が遮るのはこの一部であり、端末上のすべてのコピーではありません。まずサーバー側を遮ることが、一度きりの共有の前提です。
鍵を POST フォームに入れても解決ではありません。作成 API が平文や鍵を JSON に書けば、サーバーは読めます。正しい制約は、ブラウザを出るのは暗号文番号と暗号文だけ。解ける材料は、ログに入るどの欄にも出てはいけません。
HTTPS は対向がクエリを読むのを止めない
TLS が守るのは経路上の盗聴者です。オリジンが TLS を終端したあと手にするのは復号後のリクエスト行です。クエリはサーバーにとって平文。fragment はこのリクエストにそもそも現れません。
# の後ろは HTTP でどこへ行くか
URI はプロトコル、ホスト、経路、クエリ、断片に分かれます。断片(fragment)は # で始まり、もともと頁内アンカー用です。仕様は、ユーザーエージェントが文書を取るとき断片を外してから送ることを求めます。HTTP リクエスト行に #... の欄はなく、プロキシもオリジンも access log に書けません。
ページが載ったあと、スクリプトは location.hash で井号の後ろを読めます。クライアントメモリの文字列であり、サーバーが返した欄ではありません。閲覧の典型は、経路またはクエリの番号で暗号文を取り、端末で読んだ鍵で AES-GCM 復号することです。サーバーは最初から最後まで暗号文だけを扱います。鍵がなければ、暗号文は役に立ちません。
MyPassGen のゼロ知識閲覧後消滅はこの順です。ブラウザで AES-256-GCM 暗号、乱数 256 ビット鍵を Base64URL にして # の後ろへ。上がるのは暗号文と期限、閲覧回数などのメタです。閲覧ページは受け手に公開で、相手の先登録は不要です。一度きりの共有に同僚のアカウントを開かせたら、鎖はすでに切れています。初回の成功閲覧後、暗号文は設計どおり破棄されます。これは製品事実であり、「サーバーが見ないと保証する」ではありません。
リクエストに見えるべきもの、見えてはいけないもの
作成時の POST 本体には暗号文があるべきで、今入力した原文も、# の後ろに後で出る鍵もあってはいけません。閲覧の GET は暗号文番号だけ。開発者ツールのリクエスト URL は # の前で止まるはずです。今作った鍵の部分がリクエストに当たれば、実装が鍵を置き間違えたか、分析スクリプトが完全な location.href を送ったかです。
| URL の段 | 例 | サーバー / プロキシは見えるか | 鍵を置いてよいか |
|---|---|---|---|
| 経路 | /s.html または /s/{id} |
見える。access log に入る | 暗号文番号だけ。鍵は置かない |
| クエリ | ?id=abc&key=… |
全体が見える。既定でログへ | 不向き。key= はログに書くこと |
| Fragment | # の後ろの Base64URL 鍵 |
HTTP リクエストにこの段はない | 「ブラウザだけ」の鍵の通路に向く |
| リクエスト本体 | 作成時の JSON | オリジンは見える。一部プロキシはサンプリングする | 暗号文と機微でないメタだけ |
ここでの「ゼロ知識」は狭い。サーバーが残しても解けない、という意味です。「何も残さない」でも、「完全なリンクを持った人が解けない」でもありません。完全なリンクは持てば復号できる証。 # の後ろが無ければ解けず、一通写せば鍵が一本増えます。
Network パネルで鍵が回線に乗ったかを確かめる
スローガンは自らを証明できません。次の手順はブラウザ付属の開発者ツールだけに依ります。「リンクに鍵があるからサーバーは見た」「ページにローカル暗号と書いてあるから外へ出ていない」の両方を暴きます。形式的証明ではなく、このクリックが鍵を HTTP に入れたかを確かめることです。
井号付きのテストリンクを用意する。今作った閲覧後消滅でも、任意の端末ページに #TESTKEY-確認専用 を足したものでも構いません。先に # 以降をメモ帳へコピーし、あとで検索します。
Network を開き、Preserve log を入れる。Chrome、Edge、Firefox で構いません。フィルタはまず Fetch/XHR と文書、それから全部。Preserve log は遷移で記録が消えるのを防ぎます。アドレス欄には完全 URL が見えますが、それはブラウザの表示であり、回線に乗った内容ではありません。
リンクを開くか、Enter で移動する。リクエスト一覧で文書と続く XHR を開きます。Request URL は # の前で止まるはずです。クエリに暗号文番号はあってよく、メモ帳の鍵は出てはいけません。
鍵の部分でパネル全体を検索する。Network の検索欄に鍵、または静的スクリプトに偶然出なさそうな部分を貼ります。どのリクエストも当たらなければ、少なくともこの移動は fragment を HTTP 内容として出していません。
誤った書き方を一度対照する。同じ鍵を ?key= に移してもう一度開きます(実害の無いテスト値で)。今度の検索はリクエスト URL に当たるはずです。二つの結果を並べると、どの図よりはっきりします。
作成動作で原文をもう一度検索する。閲覧後消滅の作成ページでテスト用の仮パスワードを送ったなら、その原文で POST 本体を検索します。当たるべきは暗号文欄の形であり、原文そのものではありません。鍵欄も出ないはずです。閲覧は受け手に公開で、先のログインは不要です。
この手順が証明できること、できないこと
Network が確かめるのは、今回の操作が鍵や原文を HTTP に入れたかです。悪意ある拡張、XSS で差し込まれたスクリプト、社内 SSL 復号プロキシのあとのページは見えません。「鍵がクエリにある」を暴くには足ります。エンドポイント安全の証明だと思わないでください。
Fragment はログを遮るが、リンク全体の転送は遮らない
鍵を # の後ろに置くと解けるのは、「オリジンとプロキシが既定で鍵を読める」ことです。次の経路は残ります。期待に書く方が、アルゴリズムの三文字を刷るより役立ちます。
完全なリンクは持てば復号できる
経路と fragment を手にした人は、破棄または期限まで閲覧ページで暗号文を解けます。チャット履歴、メール保管、ブラウザ履歴、画面共有、肩越しは HTTP 仕様の外です。閲覧後消滅が減らすのは繰り返し開くことと、サーバーが平文を長く持つことであり、相手のスクリーンショットや再転送は止められません。
Referer、プレビューカード、分析スクリプト
現代のブラウザは Referer に fragment を含めないことが多い。しかし「ページ自身が location.href を分析イベントに書く」実装は救えません。作成や閲覧が完全アドレスを計測属性として上げれば、鍵はクライアント経路から漏れ、サーバーの access log がきれいであっても無意味です。計測リクエストも同じ鍵でもう一度検索してください。
チャットやメールのリンクプレビューは # 以降を残すとは限りません。経路だけ取るクローラもあり、プレビューは失敗しても鍵は貼った原文に残ります。短縮で fragment を落とすものもあり、相手は「リンクが不完全」とだけ見ます。送る前にシークレット窓で自分で一度開き、閲覧が復号できることを確かめる方が、「そのまま開く」を信じるより確かです。
ブラウザ履歴とローカルスクリプト
アドレス欄の完全 URL は履歴に入ります。共用パソコンや履歴同期のプロファイルは、期限前まで有効な鍵を残すのと同じです。XSS や乗っ取られたスクリプトは location.hash を読めます。Web Crypto が守るのは誠実なページでの鍵操作であり、「悪意あるスクリプトが同一オリジンに入ったあと」ではありません。エンドポイントとフロント供給鎖の問題であり、「サーバーが鍵を持つべきでない」とは分けます。
# の後ろに残すもの、サーバーへ出してよいもの
端末に残し、fragment 経由でのみ受け手のブラウザへ渡してよいのは、平文をすぐ戻せる材料、つまり対称鍵そのものです。クエリやリクエスト本体に入った瞬間、ゼロ知識の話は切れます。
端末を出てよいのはサーバーに無用なデータだけです。暗号文 blob、推測できない番号、期限、最大閲覧回数。MyPassGen の閲覧後消滅は 1 件 32 KB まで。パスワード、API キーの断片、短い説明向きで、ディスクイメージ全体には向きません。大きいファイルは先に端末で .lock / .enc にして別経路です。サーバーは初回の成功閲覧後に暗号文を消し、期限切れ未読も消します。サーバーに平文コピーはなく、リンクを失くしても「サポートに復元」はできません。
「ページがスクリプトを取った」と「鍵を上げた」を混ぜないでください。静的リソースは普通です。探すのは、鍵の部分がリクエスト URL、Query、Payload、独自ヘッダに出たかです。本サイトも鍵や原文を分析イベントの中身にしません。イベントに秘密そのものは出ないはずです。
鍵を同僚へ渡し、サーバーログに書きたくないとき
よくある代替の限界は具体的です。平文メールとチャットはパスワードを双方の履歴、サーバー保管、端末バックアップに残し、期限が来ても相手の分は消えません。ネットディスクは先に端末で暗号化して暗号文を上げない限りサーバーが読めます。鍵をクエリに置くのは、リバースプロキシにメモを頼むのと同じです。不便なのではなく、平文の窓がプロトコルに書いてあります。
短いテキストの秘密——root パスワード、復旧コード、短い接続文字列——に要るのは、端末暗号、鍵が HTTP に乗らないこと、受け手が開けば見られ、見終われば暗号文が消えることです。MyPassGen の閲覧後消滅リンクはこの制約で動きます。AES-256-GCM はブラウザで終わり、鍵は # の後ろ、サーバーは暗号文だけを一時保管。作成も閲覧も登録不要です。Network を開き、上の手順で今コピーした鍵を検索すれば、「ログに出てはいけない一段」が回線に乗ったかを確かめられます。
32 KB を超える、または何度でも復号できる控えが要るときは、ファイル箱で端末の .lock / .enc を作り、運び方は自分で選びます。閲覧後消滅が解くのは「一度だけ見る短い秘密」であり、ネットディスクの代わりではありません。機微な計算をなぜ既定でサーバーに渡してはいけないかは、前稿なぜ暗号計算をブラウザのローカルに置くのかが平文の窓をより開きます。本篇が求めるのは、このリンクが開かれたとき鍵がまだ井号の後ろにあり、リクエスト行に走っていないか、答えられることです。