注文リンクは鍵そのもの:何が晒されるのか
2026年11月3日に実際の100 USDT注文を作成し、Cookieも認証もなしで読み返しました。10フィールド、失効なし、そして完全なURLを受け取る第三者のスクリプトが1つ。注文リンクの正体を実測します。
2026年11月3日10:03:11 UTC、私たちはveilswap.ioで実際に注文を作成しました。100 USDT(TRON)→XMR。応答は5フィールドだけ——ID 4192151d-…、入金先 TUTmcejZAXe2nGhoJ6CJ5Fz8qHn9QMuvTs、0.13951129 XMR、状態 waiting_deposit、そして601秒後の締切10:13:12。その瞬間以降のすべては1つの文字列を通じて起きます:https://veilswap.io/order/4192151d-04c6-4595-936c-48b15a4ad0c6。アカウントもメールもパスワードもありません。リンクそのものが資格情報であり、本稿はそれが何を、誰に、いつまで渡すのかを扱います。 (XMR→USDT 出口ルート)
この設計は意図的で、代償も意図的です。 アカウントなしの交換所はログインを求められない代わりに、持ち運べるものを渡す必要があります。それがURLです。ordersテーブルは20列で、email・phone・nameはありません。注文を回復する第二の経路も、あなたと購入を結ぶ第二の識別子も存在しないということです。交換条件はこうです——あなたとスワップの間のリンクを1本減らし、自分で守る秘密を1つ増やす。強度は本物で、本番DBの143件すべてがuuid v4、122ビットのランダムです。毎秒10億回の推測で期待値は約1.7×10^20年。攻撃は推測ではなく、持ち運びの側にあります。
リンクが実際に渡すもの。 CookieもAuthorizationも付けずに GET /api/order/<id> を叩くと、200と10フィールドが返ります:depositAddress、depositExtraId、fromAmount、fromAsset、toAsset、toAmount、status、providerStatus、validUntil、id。ヘッダは cache-control: no-store。to_address と refund_address は返しません(サーバ側に残ります)。終端状態になると payinHash と payoutHash も返さなくなります——支払い済みの注文で確認したところ、両キーが消えていました。つまり漏れたリンクは「何を・いくら・どの入金先に・どこまで進んだか」を他人に渡し、「最終的にどこへ行ったか」は渡しません。決済後は取引ハッシュも渡しません。
失効するのは支払い窓だけで、リンクではありません。 601秒は入金の窓です。10:04 UTCに09:24:55作成・返金済みの注文を読み返すと、作成から39分後でも入金先とvalidUntilがそのまま返りました。コードも同じで、注文ルートはGETのみ、PATCH・PUT・DELETEはなく、ローテーションも失効も「注文削除」もありません。さらに輪をかける事実があります。143件の注文に対して入金先は134個しかなく、うち2つのアドレスが7件と4件を引き受けていました。リンクがそうしたアドレスを指すとき、それは私的なアドレスではなく複数の注文が通った共有アドレスへのポインタです。この再利用はプール側の割り当てでありリンクの不具合ではありませんが、リンクが明かす内容を変えます——自分の注文だけでなく、複数の注文が通過したアドレスを指すのです。
ローカルに3つの複製が残り、どれも私たちの手の外にあります。 ブラウザ履歴はURLを保持し、同期はログイン中の全端末へ複製します。注文ページのスクリーンショットには通常、入金先を符号化したQRコードとアドレスバーの両方が写ります。取引ウィジェットは vs_active_order をlocalStorageに書き、注文ID・入金先・extra id・両方の金額・両方の資産IDを含めます。削除されるのは終端状態を受け取ったときだけです。共用ノートPCで支払わずにタブを閉じれば、昨日の入金先がそのプロファイルに残ります。sessionStorageの vs_order_session は /exchange が旧注文を自動復帰するかだけを決め、記録を残すかは決めません。これら3つの複製は私たちから見えず、こちら側から失効させることもできません。だからリンクは「サイトが守るもの」ではなく「あなたが持ち運ぶもの」として扱う必要があります。
ページ自体がURLを見る第三者を1つ積んでいます。 /order/<id> のHTMLは32,795バイト、noindex・nofollowのrobotsメタを持ち、Cookieを設定せず、cache-control: no-storeを返します。01a0d6f6-4444-7a6d-a45f-6375a01eba8f.spst2.com から ustat.js(3,560バイト)を読み込みます。中身を読むと、location.href を url フィールドに入れ、referrer・画面サイズ・言語・canvasフィンガープリントを集め、/api/report へPOSTします。交換ページで動くClarityは注文ページには0箇所(すでに除外済み)ですが、この小さい計測スクリプトは完全な注文URLを受け取ります。referrer-policy: strict-origin-when-cross-origin はクロスサイトのRefererをオリジンまで削るだけで、自分で読み込んだスクリプトが location を読むことは止めません。これが私たちの基盤の外へ完全に出ていく唯一の経路です。
こちら側ではリンクは1行のログに落ちます。 nginxの書式は remote_addr、CF-Connecting-IP からの実クライアントIP、時刻、完全なUUIDを含むリクエスト行、ステータス、バイト数、UAを記録します。ログは日次でローテーションし14世代保持、つまり常時およそ15日分の「IP↔注文」対応表が存在します。その窓で数えたところ、注文ページの表示83回、APIポーリング738回、149の注文ID。61の異なる注文パスのうち6つが複数のクライアントIPから取得され、API側では8件が複数アドレス(最大3)からポーリングされました。bot UAが4パスを取得し、そのうち3パスは人間のUAも記録していました。リンクをチャットに貼ったときにサーバ側で起きることです——プレビューボットは受取人がクリックする前に、数分で来ます。404側は120リクエスト・82パス・9IPで、最も多い送信元は /api/order/1 と /api/order/callback。汎用スキャナであり列挙ではありません。成功した総当たりは観測しておらず、122ビットでは起きるはずもありません。
リンクを持つ人ができること、できないこと。 できないのは、受取先の変更、返金先の変更、キャンセル、資金の移動。書き込みエンドポイントはなく、両アドレスは作成時に固定されます。入金先へ送金しても、それは自分の注文を支払うだけです。できるのは、金額と通貨ペアを読むこと、入金先をオンチェーンで監視すること、状態を好きなだけポーリングすること。GETを40回連続で叩いて40回とも200でした——読み取りにアプリ層のレート制限はありません(見積にはあり、注文作成は1時間あたりIP6件まで)。現実的な被害は開示とソーシャルエンジニアリングです。注文ID・金額・「まだ未払い」を知る人物は、内部者しか知らないはずの情報を添えてサポートを名乗れますし、入金先を監視して入金の瞬間を見ることもできます。後者のほうが静かです。監視された入金先はあなたのタイミングを明かし、タイミングはしばしば、そのスワップを直前の出来事と結び付けるのに足ります。
コストゼロの習慣。 1)URL全体をチャット・サポートチケット・スクリーンショットに貼らない。送るなら入金先と金額、またはアドレスバーを切る。2)残すならパスワードマネージャの項目として(日付と通貨ペアで命名)、ブラウザ履歴だけに置かない。3)paid・expired・refunded になったら一度ページを開いて vs_active_order を消させ、共用機ならサイトデータも消す。4)他人のPCではプライベートウィンドウ。5)助けが必要なら完全なIDを渡す前提で——サポートはIDなしで注文を引けません。秘密が出ていく唯一の場所なので、パスワードを送るのと同じ経路を使ってください。6)枠組みを間違えないこと。リンクは「読み取り権限」で、財布ではありません。失っても資金は失われず(支払い済みの注文はそのまま決済されます)、渡しても資金は動きません(アドレスは変更できないからです)。2点は名指しする価値があります。計測スクリプトは注文ページで動くべきではありません(完全なURLを第三者に渡すため)。入金先の再利用はページに表示すべきです(現在143件が134個を共有)。