JustDropFile

仕組み

JustDropFile は、すべてブラウザの中で動くピアツーピアのファイル転送です。このページでは各ステップをごまかさずに説明します。信頼できるかどうかは、自分で判断してください。

1

ファイルをドロップするとリンクができる

ブラウザが 2 つのランダムな値を生成します。128 ビットのセッション ID と 256 ビットの暗号鍵です。それをもとに justdropfile.com/r/#セッション.鍵 のようなリンクを組み立てます。転送の識別情報はすべて # 以降、フラグメントと呼ばれる部分にあり、ブラウザはフラグメントをどのサーバーにも送りません。この時点で端末から出ていったのは、セッション ID を運ぶシグナリングサービスへの WebSocket 接続 1 本だけです。

  • •QR コードは同じリンクを、端末上で描画したものです。
  • •誰も開かなければリンクは 20 分間有効で、その後セッションは破棄されます。
2

相手がリンクを開き、ブラウザ同士が見つけ合う

受信側のブラウザはフラグメントを読み、同じセッション ID でシグナリングサービスに接続し、2 つのブラウザはそれを介して接続情報(SDP と ICE 候補)を交換します。サーバーの仕事はそれだけです。ちょうど 2 つのピアの間で数キロバイトのハンドシェイクを受け渡すこと。3 人目は拒否し、接続情報は記録せず、ピア同士がつながった瞬間にセッションを削除します。

Technical note:

シグナリングサービスは、セッションごとに 1 つの Durable Object を持つ Cloudflare Worker です。セッションの作成には IP ごとのレート制限があります。記録されるのは集計カウンターだけで、接続情報の本体は記録されません。

3

まず直接接続を試す

WebRTC は 3 つの経路を順番に試します。ローカルネットワーク内の直接経路、STUN で公開アドレスを調べてインターネット越しにつなぐ直接経路、そして最後に中継です。家庭やモバイルのネットワークのほとんどは、最初の 2 つのどちらかを通します。接続自体は WebRTC の要件どおり DTLS で暗号化されます。

  • •直接接続にサイズの上限はありません。
  • •接続後、ページはどの経路が選ばれたかを確認し、「直接」か「中継」かを表示します。
4

直接接続に失敗したら、暗号化された中継が引き継ぐ

オフィス、病院、大学、ホテルなどのネットワークの中には、端末同士の直接接続を完全にブロックするものがあります。その場合、通信は Cloudflare TURN を経由して中継されます。中継サーバーは暗号文を転送するだけで、鍵は持っていません。中継の認証情報はセッションごとに私たちの Worker が発行し、期限切れになるので、中継を無料のプロキシとして流用することはできません。中継されるバイトには費用がかかるため、中継経由の転送は 2 GB までです。

Technical note:

Cloudflare TURN は、セッションごとに生成される短命の認証情報で使われます。中継までブロックされている場合、ページはその旨を伝え、別のネットワークかスマホのテザリングを提案します。

5

受信者がファイル一覧を見て受け入れる

ファイルのバイトが 1 つでも動く前に、送信者は暗号化されたマニフェスト(ファイル名、サイズ、種類)を送ります。これはシグナリングではなくピア接続を通るので、私たちのサーバーには決して見えません。受信者は拒否できます。受け入れると、受信側のブラウザはファイルを書き込む場所を開きます。あなたが選んだフォルダ(デスクトップの Chrome と Edge)か、ブラウザの非公開ディスクストレージ(Safari、Firefox、Android)です。これにより、ファイルはメモリに溜め込まれるのではなく、到着するそばからディスクに書き込まれます。

6

ファイルは暗号化された断片として流れる

送信者はファイルを最大 64 KB の断片に分けて読み、それぞれをリンクの鍵を使って AES-GCM で暗号化し、WebRTC データチャネルで送ります。各断片はファイル番号と位置番号を認証付きデータとして持つので、壊れた断片、欠けた断片、順序が入れ替わった断片、再送された断片は検証に失敗します。各ファイルの終わりに送信者は署名付きの断片数とバイト合計を送り、受信者は両方を確認してから受領を返します。ファイルは 1 本の接続で順番に送られます。

  • •どちらの側もファイル全体をメモリに持つことはありません。数ギガバイトの転送もスマホで動きます。
  • •送信者はチャネルのバックプレッシャーに従うので、受信側が遅ければ送信側が遅くなり、メモリがあふれることはありません。
  • •接続が切れた場合、転送は明確に失敗し、送信者は新しいリンクを作れます。このバージョンに再開機能はありません。

自分で確かめる

ブラウザの開発者ツールを開いて「ネットワーク」タブに移動し、転送を実行してみてください。シグナリングホストへの WebSocket が 1 本、小さな JSON メッセージを運んでいるのが見えるだけで、それ以外は何もありません。アップロードのリクエストも、ファイルのバイトもありません。転送自体は WebRTC の内部情報(Chrome では chrome://webrtc-internals)に表示され、選ばれた候補ペアが直接か中継かもそこで確認できます。

鍵は URL のフラグメントにあるため、どのリクエストにも現れません。同じ「ネットワーク」タブで確認できます。シグナリングホストへのリクエストにはセッション ID が含まれ、ドットより後ろには何もありません。

この設計にできないこと

  • •オフラインの相手には届けられません。保存場所がないので、両側がその場にいる必要があります。
  • •相手からあなたの IP アドレスを隠すことはできません。ピア接続はアドレスを交換することで成り立っています。
  • •直接接続と TURN 中継の両方をブロックするネットワークは通過できません。
  • •切れた転送を再開することはできません。新しいリンクで最初からやり直します。