ワンタイムリンクはサーバーが暗号文を消したことは証明できても、相手が画面撮影していないことは証明できない

一度きりのパスワードをワンタイムリンクにして送る。相手が開いたあと再読み込みすると、「削除済み」と出る。これを「見た瞬間に消えた。何も残らない」と話す人は多い。消えたのはサーバー上の暗号文です。相手の画面に出た文字、システムのスクリーンショット、チャットに残った完全な URL は、この削除を通りません。その場で照合できるのは、同じ番号でもう一度暗号文を取りに行ったとき、サーバーがまだ渡すかどうかです。

先に結論を狭く置きます。閲覧回数に達した、または期限が切れたあと、サーバー上の暗号文はなく、同じ番号でもう一度原文は取れません。ここまでは言えます。「相手は画面撮影していない」「グループに第三者がいない」「チャットのバックアップに完全なリンクがない」は言えません。照合するのは、二度開くことと Network です。ページ上の「削除済み」を、相手の端末がきれいである証拠にしないでください。

検索意図に一文で答える

ワンタイムリンクが支えられる結論は一つです。預かった側が持っていた暗号文は消えた。受信側の画面、クリップボード、チャット履歴が消えた、とは言えません。一度暗号文の取り出しに成功したあと、同じリンクをもう一度開くと、閲覧ページは削除済み、または期限切れを出します。HTTP 410 Gone の意味は、元の場所にもう対象リソースがなく、その状態は多くの場合永続である、ということです。答えられるのは「サーバーはまだ渡すか」です。「相手は写しを残したか」には答えません。

このノートは開発者、運用、そして一度きりのパスワード、API キー、リカバリーコードを同僚へ送る前に、「リンクが無効になった」と「相手は何も残していない」を分けたい人向けです。ワンタイムリンク の操作説明の代わりにはならず、「リンクの作り方」も繰り返しません。持ち帰るべきなのは、消えたのがどの層か、再読み込みの失敗が証明できる範囲、画面撮影がなぜその外にあるか、二度開くことと Network でホスト側をその場で照合する方法です。

「削除済み」と「相手は写しを残していない」は別の事実

日常の言い方は、三つの違う事実を「このメッセージは見終わると消える」の一文に畳みます。第一は、サーバーが暗号文を持たなくなったことです。番号に対応する記録は消え、次の要求は削除済みか期限切れだけを返します。第二は、今のタブが平文を出さなくなったことです。ページを閉じる、「このページから消す」を押す、離れるときに入力欄を空にするスクリプトが、ここに効きます。第三は、受信側の端末に写しがないことです。スクリーンショットも、コピーも、完全なリンクの転送も、平文をチャットへ戻すこともない、という状態です。

ワンタイムリンクが強制できるのは第一だけです。第二は、せいぜい「このタブの表示欄を空にした」までです。第三には手が届きません。閲覧ページが「コピーや画面撮影は止められない」と書くのは、遠慮ではありません。境界です。普通のウェブページは、別のスマートフォンが画面を撮ることを禁じられません。「平文をコピー」のあと、システムのクリップボードやチャットアプリのローカル保存を消して回る権限もありません。

ですから「こちらで再読み込みしたら、もう開けない」が支えられる結論は狭いです。今回、番号で暗号文を取りに行ったとき、サーバーは渡さなかった。それだけです。「開いたのは指定した同僚だけ」「画面撮影していない」「チケット検索にこの文字列は二度と出ない」は支えられません。後ろの文を照合できる事実にするなら、観察を変えてください。平文や完全な URL が、このタブの外へ出たか。送信側自身の二度目のオープンではありません。

サーバーが消すのはどの層か

ゼロ知識のワンタイムリンクは、「探す」と「開く」を分けます。形は s.html?id={id}#{key} です。疑問符の後ろは番号だけ、鍵はハッシュの後ろだけです。RFC 9110 は、リクエストの対象 URI にフラグメントを含めないと書いています。ブラウザが文書を取りに行くとき、# とその後ろを落とします。サーバーが見るのは設計どおり番号だけです。鍵も平文も見えません。

作成時、このタブは Web Crypto で AES-256-GCM を使います。32 バイトの乱数鍵、12 バイトの IV、平文はこの端末で暗号文になってから POST /secrets します。出ていく欄は暗号文、有効期限、閲覧回数です。鍵は、あとから組み立てる共有リンクにだけ現れます。一件の上限は 32 KB。期限は 1 時間、24 時間、7 日、または閲覧後だけ削除です。閲覧回数は 1〜10、初期値は 1。作成も閲覧も開いてすぐ使えます。アカウントはなく、「誰が開いたか」のログイン身元もありません。

閲覧時、サーバーは暗号文を渡し、設定した回数に達したあと、その暗号文を削除します。送信側がもう一度開くと、削除済みか期限切れです。これで言えるのは、預かった側がもうその暗号文のバイト列を持っていない、ということです。鍵がチャット履歴に一度も出ていない、平文が相手の画面に一度も出ていない、第三者が同じ完全な URL で「開いて見る」を押していない、とは言えません。

完全な URL を持っている人は、鍵も持っています。https://…/s.html?id=…#… をグループへ貼ることは、番号と鍵を同時に渡すことです。サーバーが暗号文を消したあとでも、すでに開いて平文を残した人は巻き戻せません。回数が残っていれば、あとから押した人も暗号文を取れます。暗号文を消すのは、「ホストが平文や暗号文を長く持つ」層の話です。「文字列全体を見た人」の層ではありません。

再読み込みの失敗が証明できること、できないこと

二度目が失敗したとき、表示は一つではありません。三つに分けてください。第一は削除済みです。暗号文はもうなく、設定した回数を使い切ったか、番号がもともと無効かです。第二は期限切れです。作成時に選んだ TTL が来たので、誰も読んでいなくてもサーバーは消します。第三はフラグメント鍵がありませんです。番号は残っていても、この端末では開けません。LINE、Slack、Teams、一部のメールクライアントは、# 以降を切ります。受信側が見るのは「フラグメント鍵がありません」であり、「誰かが先に読んだ」とは別の出来事です。

410 Gone は、元の場所にもう対象リソースがなく、その状態はおそらく永続である、という意味です。閲覧ページは 410 を削除済みと期限切れに分けます。応答に expired があれば TTL、なければ削除済みとして扱います。404 も削除済みとして出します。受信側から見れば結果は同じで、暗号文はもう取れないからです。ネットワーク失敗は削除ではありません。「開いて見る」のあと回線が切れ、作成時に 1 回だけ読んでよかった場合、暗号文はすでに取られていても、このタブでは開けていないことがあります。

ですから「こちらで再読み込みしたら開けない」が支えられるのは、いまこの番号ではサーバーが暗号文を渡さない、ということです。開いた人が指名した同僚である、コピーしていない、画面撮影していない、プレビューやセキュリティスキャナが先に回数を使っていない、は支えられません。アカウントがなければ、名前の付いた既読通知はありません。回数はサーバー側のカウンタです。受信側の端末の監査ではありません。

本物のパスワード、API キー、伏せていない接続文字列で試さないでください。今回だけ使うテスト文を書いてください。照合するのは状態照会、暗号文を取る要求、二度目の表示です。生きている資格情報をもう一度晒すことではありません。

画面撮影、コピー、チャット履歴が範囲外である理由

平文が画面に描かれた瞬間、問いは「サーバーはまだ暗号文を持つか」から「相手の端末で何が起きたか」へ移ります。システムのスクリーンショット、画面録画、別のスマートフォンで画面を撮る行為は、ホストへ要求を送りません。閲覧ページはそれを止められず、あとから知らせることもできません。ある製品の未完成項目ではありません。普通のウェブページに、「相手が自分の画面を記録することを禁じる」スイッチは渡されていません。企業向けの DLP や DRM が OS 層で画面キャプチャを制限することがあるのは、別の仕組みです。公開の閲覧ページが同じ力を持つわけではありません。

コピーも同じ柵の外です。閲覧ページは「平文をコピー」を出せます。離れるときに入力欄を空にもできます。空になるのは、この DOM のノードです。システムのクリップボードでも、チャットの下書きでもありません。macOS や一部の入力方式は、クリップボード履歴を残します。「このページから消去済み」は、今のタブがもうその文を出していない、という意味だけです。クリップボードに一度も入っていない、という意味ではありません。

チャット履歴は、また別の保存です。完全なリンクがグループに出たなら、履歴、検索、複数端末の同期、あとからの書き出しは、ハッシュ以降の鍵をもう一度見せます。サーバーが暗号文を消したあとでも、URL 自体は「かつて有効だった」痕跡です。回数を使い切ったと知らない人が何度も押し、「リンクが壊れた」と誤るには十分です。HTTP の層はきれいなままです。Referer は仕様上フラグメントを運んではいけません。ただし、チャット履歴を開ける人に対して、この層はもうありません。

チケット、メール、ブラウザ履歴も同じ分かれ方です。アドレスバーに出た # フラグメントは、たいていローカル履歴に入ります。同期しているブラウザなら、同じ行を別の端末へ送ることがあります。タブを閉じることは、履歴を消すことではありません。ワンタイムリンクが短くするのは、サーバーが塊を持つ時間と、同じ暗号文を何度も取れる回数です。デジタル著作権管理でも、鑑識報告でもありません。

状態照会が回数を消費しない理由

着地ページを開いた瞬間に暗号文を取ると、チャットのプレビュー、メールのセキュリティゲートウェイ、社内スキャナが、受信側より先に唯一の回数を使い切れます。受信側が開いたときには削除済みです。鍵はプレビュー側のホストへ渡っていません。消えたのは閲覧回数であり、フラグメントの秘密ではありません。前のノートは、ハッシュがデフォルトで HTTP に入らない理由を書いています。本稿は回数だけを見ます。プレビューの要求と、本当に暗号文を取る要求を分けないと、「削除済み」は「受信側が見た」すら支えられません。

FastPwd の閲覧ページは、この二段を分けています。ページを開いたときは /secrets/{id}/status だけを呼び、暗号文がまだあるかを尋ね、塊は取りません。受信側が「開いて見る」を押したあと、タブは GET /secrets/{id} し、# の後ろの鍵でこの端末で復号します。# 鍵がないときは、暗号文を取りに行きません。残っている回数を無駄にしないためです。作成ページも閲覧ページも、アカウントは不要です。

プレビュー用のボットは、たいてい着地ページだけを取り、ボタンは押しません。「プレビュー即削除」の確率は下がります。すべてのスキャナがそこで止まる証明にはなりません。Network では、先に状態照会、あとで暗号文の取り出しが見えるはずです。開いただけ、押していないときは、塊を取った成功応答は出てはいけません。回数はなおサーバー側のカウンタです。フラグメントの一部ではありません。

見える現象 支えられる結論 支えられない結論
二度目に削除済みと出る いまこの番号では暗号文を取れない 相手は画面撮影もコピーもしていない
期限切れと出る TTL が来て、サーバーが消した 誰かが必ず読んだ
フラグメント鍵がありませんと出る アドレスに # 以降の鍵がない 暗号文はすでに取られている
ページは開いた。ボタンは押していない 状態照会は回数を消費しないはず すべてのプレビューボットが暗号文を取らない
Network の POST に暗号文だけがある 今回の作成は原文を業務欄として出していない 完全なリンクをチャットへ貼ったあとも、見えるのは自分だけ
このページから平文を消した 今のタブはもうその文を出していない クリップボードとスクリーンショットにもない

その場で照合する:二度開く、状態照会、Network

標語は証拠になりません。捨ててよいカナリアを用意してください。例は canary-fp-20260905-burn-vs-shot です。生きているパスワードを使い回さないでください。閲覧回数は初期値の 1 のまま、期限は 24 時間で足ります。

  1. 作成ページにカナリアを書き、リンクを作ります。開発者ツールの Network を開き、Preserve log を入れてください。カナリアとハッシュ以降の鍵を別々に検索します。POST /secrets の本文に出るべきなのは暗号文、有効期限、閲覧回数です。原文も鍵も出てはいけません。
  2. 同じ完全なリンクで閲覧ページを開きます。まだ「開いて見る」は押さないでください。Network に /secrets/{id}/status は出て、塊を取った成功の GET /secrets/{id} は出てはいけません。ページは確認待ちのままです。
  3. 「開いて見る」を押します。ここです番号で暗号文を取り、この端末で AES-256-GCM により開くはずです。成功後の説明は、サーバーがこの暗号文を削除した、と書きます。回数を 1 より大きくした場合は、設定した回数に達してから削除します。
  4. 閲覧ページを再読み込みするか、新しいブラウザの文脈でもう一度同じリンクを開きます。1 回読みの初期値なら、削除済みと出るはずです。Network をもう一度検索してください。暗号文を取る要求は 410、または削除済みとして扱う応答を返すはずです。カナリアが平文として、どのリクエスト本文にも再登場してはいけません。

この四段が証明するのは一件だけです。あなたが制御した二度のオープンのあいだに、サーバー上の暗号文が「ある」から「ない」へ変わった。もしこれが同僚向けの本物のパスワードだったとして、相手が画面撮影していない、とは言えません。「相手は残すか」は引き継ぎの文に書いてください。画面を撮らない、平文をグループへ戻さない、使い終わったらすぐ回す。ページ上の「削除済み」が、相手の端末を監査してくれる、と期待しないでください。

完全なリンクと暗号文を、同じ経路で送らないでください。.lock はドライブやメールへ、パスフレーズはワンタイムリンクへ。ワンタイムリンクの完全な URL を、そのフォルダのメモへ戻さないでください。鍵と箱が同じメッセージに乗ると、暗号文を消しても、文字列全体を見た人は助けられません。

「削除済み」を読み過ぎる三つの場面

第一は、期限切れを「誰かが読んだ」と読むことです。作成時に 1 時間を選び、同僚が翌日押すと、表示は期限切れです。サーバーは暗号文を消しました。理由は TTL であり、閲覧回数の使い切りではありません。期限切れで未読の内容は戻せません。「すでに開かれた」とも言えません。

第二は、フラグメント不足をすでに削除済みと読むことです。LINE、Slack、一部のメールクライアントは # 以降を切ります。受信側が開くのは s.html?id=… で、鍵はありません。閲覧ページは、鍵がないときは暗号文を取りません。あとから完全なリンクを開くと、内容はまだ残っていることがあります。相手にハッシュを含む文字列全体を送り直してもらってください。「誰かが先に見た」と決めないでください。

第三は、このページから消すことを全体の消去と読むことです。閲覧ページは離れるときに入力欄を空にできます。history.replaceState でアドレスバーからフラグメントを外すこともできます。変わるのは、今のタブの表示と、あとからの再読み込みがまだ鍵を持つかです。システムのスクリーンショット、クリップボード履歴、チャットのバックアップ、同期したブラウザ履歴は、この消去の外です。

よくある質問

相手が再読み込みして「削除済み」を見たら、内容は残っていないと言えますか?

言えません。言えるのは、サーバー上の暗号文がもうなく、同じ番号でもう一度原文を取れないことだけです。スクリーンショット、コピー、画面録画、チャットのバックアップ、完全なリンクの転送は、この削除を通りません。削除済みは、相手の端末がきれいである証明ではありません。

チャットのリンクプレビューが先に内容を消してしまいませんか?

プレビューは、たいてい着地ページだけを開きます。閲覧ページは先に暗号文が残っているかを尋ね、暗号文は取りません。「開いて見る」を押したときだけ、番号で暗号文を取ります。プレビュー用のボットは、多くがボタンを押しません。ただし、すべてのスキャナが着地ページで止まる保証はありません。回数はサーバー側のカウンタです。照合は、開いただけ、押していないときに、Network へ塊を取った成功要求が出ないことです。

ワンタイムリンクは、誰が開いたかを証明できますか?

できません。作成も閲覧もアカウントは不要で、サーバーはログイン身元で閲覧者を印しません。照合できるのは、今回暗号文を取ったあと、その番号がまだ残っているかどうかです。削除済みから名前は引き戻せません。既読通知としても書けません。

作成や閲覧に登録は必要ですか。平文はアップロードされますか?

不要です。このタブは AES-256-GCM により暗号化してから、暗号文をアップロードします。鍵は # フラグメントにあります。捨ててよいテスト文で Network を検索してください。本文に出るべきなのは暗号文であり、原文やハッシュ以降の鍵ではありません。32 KB を超える文、またはファイル全体は、ファイル暗号化 でこの端末で処理してください。ワンタイムリンクをドライブの代わりにしないでください。

同じカナリアを、開いてすぐ使えるツールで一度照合する

計算の境界をページ上に書いた場所で練習するなら、FastPwd の ワンタイムリンク を開いてください。登録は不要です。上のカナリアを書き、閲覧回数は 1 のままリンクを作り、照合の節の二度開きを終えてください。同時に Network を見てください。見えるべきなのは、作成時の暗号文 POST、閲覧ページの状態照会、クリック後の取り出し、二度目の削除応答です。原文やハッシュ以降の鍵が業務欄として出てはいけません。

パスワードを同僚へ渡さなければならないときだけ、この経路を使ってください。乱数パスワードは先に パスワード生成 でこの端末で作れます。長さは 6〜128 文字、初期値は 16 文字。8 文字未満では安全性が低いと示します。生成はアップロードしません。契約書一式、身分証のスキャン、32 KB を超える材料は ファイル暗号化 で、同じ AES-256-GCM により .lock / .enc にします。単ファイルは 5 GB までです。パスフレーズはワンタイムリンクだけで送り、ドライブのメモへ書かないでください。

次に送る前に、三つ覚えてください。第一に、削除済みが証明するのは、サーバー上の暗号文がなくなったことであり、相手が画面撮影していないことではありません。第二に、着地ページを開いただけでは回数を消費しないはずです。暗号文を取るのは「開いて見る」です。第三に、完全なリンクをチャットへ貼ったあと、ハッシュ以降の鍵は、そのメッセージを見られる人に対して平文です。繰り返せる観察だけが、自分たちの引き継ぎ説明に書く価値があります。

関連記事

ハッシュの後ろがデフォルトで HTTP に入らない理由と、完全なリンクを貼ったときに消える層は、URLの#以降に鍵を置ける理由と、その保護が崩れる場面。「ローカル暗号化、アップロードなし」は、捨ててよいテスト文で Network を検索するまで証拠になりません。ブラウザのローカル暗号化で、平文が端末を出ていないことを確認する。チケット本文の身分証番号を、端末を出る前に伏せたいときは、チケットとログをAIに貼る前に、どの欄が端末を出るかを確認する。