匿名通信プロトコル (Tor)
匿名通信プロトコルは,流れているメッセージを見ても送信者が特定できないようなネットワークプロトコルであり,その1つの方式に Tor がある.(→ 匿名通信路)
Tor とは
Tor(The Onion Router)は,TCP/IP における接続経路の匿名化を実現するための規格,及びそのリファレンス実装であるソフトウェアの名称である.Tor は,米海軍調査研究所 (NRL) が開発した通信システムをベースにオープンソース・コミュニティーが改良を加えて開発されている.Onion Routing と呼ばれる仮想回線接続により,通信を複数のノードを経由させることにより匿名性を高めている.複数ノードを経由する過程で,暗号化と復号の動作があたかもタマネギの皮を1枚ずつ重ねたり剥いだりすることに似ていることが名前の由来である.
Tor は SOCKS プロキシ (Onion Proxy:OP) として動作し,無作為に選ばれた複数の Tor サーバ (Onion Router: OR) を経由して目的のサイトへアクセスする.また.経由する Tor サーバは常に切り替えられ,経由した Tor サーバの特定を難しくしている.
Tor を使う理由は,個人が特定される情報(IPアドレス)を相手に知られないようにインターネットアクセスすることである.
特に,固定 IP アドレスから接続してる場合,IPアドレスを知られてしまうと事でハッキングや嫌がらせ等の被害を受ける事の予防になる.また,Tor には身元 (IPアドレス) を知られずに各種サーバを運用出来る機能があり,匿名で情報を発信したい場合などに利用できる.
なお,Tor は完全な匿名性を保証するものではなく,個人の特定を困難にする程度のものと考えるべきである.また.通信内容の秘匿化 (暗号化) の機能は持たない.
Tor のリファレンス実装は,Windows や macOS,Linux 等の各種 Unixライク OSで動作する.Windows 版では設定済みの Tor と Mozilla Firefox をセットにし,USBメモリに入れての利用を想定したパッケージも用意されている (https://www.torproject.org/),
Tor の特徴
- Tor は主として接続経路の匿名化を行うものであり,通信内容の秘匿化を行うものではない.Tor では経路の中間に限り暗号化を行っているが,経路の末端では暗号化が行われていない.
クライアント (Onion Proxy)と Tor サーバ (Onion Router) 間,および Tor サーバ間の通信は,TLS により暗号化が行われる.
通信内容自体の秘匿化まで行う場合は,TLS/SSL (HTTPS や SMTP over SSL)などを用いて別途暗号化を行う必要がある. Tor クライアントにバンドルされる Tor Browserでは,HTTPS Everywhereという拡張機能があらかじめインストールされている.ルール設定された主要なサイトにアクセスすると強制的に HTTPS で接続するようになっている.
- 現実装においては,TCP に対応しているが UDP 等 TCP 以外のプロトコルには対応していない. ほとんどのソフトウェアは,UDP を用いて DNS を参照するため,TCP 専用である Tor を経由せず直接参照してしまい匿名性が不完全になる可能性がある.
- Tor の中継ノードでは通常,中継のログを記録しない.中継ノードは誰でも参加できるオープンなネットワークのためログを記録するノードが紛れ込む可能性はあるが,送信者にたどり着くためには経由したすべての中継ノードのログを入手する必要がある.
- 中継経路は一定時間ごとに変更されるため,数千台から無作為に選択した複数台(通常3台) の中継ノードすべてでログを記録している可能性は非常に低く,仮に最終中継ノードが不正アクセスを受けたり,捜査機関などによって調査されたりしたとしても,本来の送信者にたどり着くことは通常困難である.
- Tor を有効にすると極端に通信速度が遅くなる.その主な原因は,Tor ネットワークが利用者に比べて非常に小さいということと,サーバをいくつか経由するため,ボトルネック(最も遅い通信経路が全体速度となってしまうこと)が発生し易いためである.
Tor の動作概要
Tor の構成と処理方式の概要を示す
(tor-design.pdf).
- セル (Cell)
Tor を構成する中継ノードである OR (Onion Router) は,他の OR およびユーザの OP (Onion Proxy) と一時的なセッション鍵を用いて TLS/SSLv3 により暗号化通信する.
通信は,固定サイズ (512 bytes) のヘッダとペイロードから構成されるセルにより行われる.ヘッダには,サーキット ID (circID) とコマンド (CMD) が含まれる.コマンドにより,セルは制御セル (そのノードで解釈されるデータ) かリレーセル (End-to-End のデータを含む中継データ) かに分けられる. リレーセルは,ペイロードの前に付加的なヘッダ (Relay header) を含む.ここには,End-to-End のデータを検査するための情報 (Digest)
が含まれる.Relay header とペイロードは,128ビットの AES 暗号 (counter mode) で暗号化される.
- 制御セル (Control cell)
CircID (2) || CMD (1) || DATA (509)
- リレーセル (Relay Cell)
CircID (2) || Relay(1) || StreamID (2) || Digest (6) || Len (2) || CMD (1) || DATA (498)
- サーキットとストリーム
Onion Routing は,基本的に各 TCP ストリームに一つのサーキット (仮想回線接続) を構築する.サーキットを構築するのには時間がかかるため (公開鍵暗号の利用やネットワーク遅延により),多くの TCP ストリームを使う Web ブラウジングのようなアプリケーションには負荷が大きくなる.
Tor では,各サーキットは多くの TCP ストリームにより共有することができる.遅延を避けるため,事前にサーキットが構築される.ユーザの OP はストリーム間の連携を制限するために,新しいサーキットを周期的に生成する.また,OP は1分間に1回新しいサーキットを使うように変更される.なお,これらのサーキットの構築はバックグラウンドで行われる.
- サーキットの構築
ユーザの OP A が目的のサイト B へのサーキットを構築する手順を示す (2つの OR を経由する場合).
- OP A は,ディレクトリサーバにアクセスし,すべての中継ノード (Tor サーバ) のリストを入手し,リストの中から無作為に複数のノード(2 つのノード OR1,OR2とする)を選択する.
- 新しいサーキットを生成するために,OP A は情報 (create cell) を新しいサーキットID c1 上の最初の OR OR1 に送る.create cell のペイロードは,Diffie-Hellman鍵交換用のデータ (gx1)を OR1 の公開鍵で暗号化したもの含んでいる.
A → OR1 : Create c1, E(gx1)
ここで,E(・) は,送信相手の公開鍵による暗号化である.
OR1 は,gy1 と共有鍵 K1=gx1y1 のハッシュ値とを返す.
OR1 → A : Created c1, gy1, H(K1)
ここで,H は暗号学的ハッシュ関数である.
A と OR1 は,鍵 K1 を共有し,以後 A - OR1 間の通信はこの暗号化通信路 (AES 暗号) を用いて行われる.
- サーキットを拡張するために,A は OR1 に次のノード OR2 のアドレスおよび暗号化した gx2 を含む情報 (relay extend cell) を送る,ここで,情報は前のステップで共有した鍵 K1 で暗号化されている.
A → OR1 : Relay c1 {Extend, OR2, E(gx2)}
ここで,{・} は,AES 暗号による暗号化を示す.
OR1 は,情報を復号して次のノード OR2 を判別し,情報を転送する.
OR1 → OR2 : Create c2, E(gx2)
OR2 は,gy2 と共有鍵 K2=gx2y2 のハッシュ値とを返す.
OR2 → OR1 : Created c2, gy2, H(K2)
OR1 は,受信情報を鍵 K1 で暗号化し,A に転送する.
OR1 → A : Relay c1 {Extended, gy2, H(K2)}
これにより,サーキットは OP2 まで拡張され,A と OP2 は鍵 K2=gx2y2 を共有する.
サーキットを3つあるいはそれ以上のノードに拡張するには,
A は上記のように常に拡張するサーキットの最終ノードを通知するようにする.
このサーキットレベルのハンドシェイクプロトコルは,一方向性のエンティティ認証である(OP は OR を認証するが, OR は相手を認証しない).
以上により,構築された A-OR1-OR2 間の仮想回線を通して,A は通信相手のサーバ B と任意の通信を行うことができる.当該回線における通信のパケットは,B から見れば,あたかも OR2 が送信元のように見える.
- リレーセル (Relay cell)
OP A がサーキットを構築すると,サーキット上の各 OR と鍵を共有し,リレーセルを送ることができるようになる. リレーセルを受信すると,OR は対応するサーキットを調べ,そのサーキットのセッション鍵でリレーヘッダとペイロードを復号する. セルが A からのものであれば,OR は復号したセルが有効な digest を持っているかを検査し,有効ならば,リレーセルを受け入れ処理を続ける. さもなくば,OR は circID とサーキットの次段の OR
を調べ, circID を適切に置き換え次の OR に復号したリレーセルを送る.
OP は入力のリレーセルを同じように扱う. リレーヘッダとペイロードをサーキット上の各 OR と共有しているセッション鍵で順番に復号していく. 任意のステージで digest が有効ならば,セルはその暗号化が取り除かれた OR で生成されたとみなされる.
サーキットを閉じるためには,
A はdestroy control cell を送信する. サーキット上の各 OR はセルを受け取ると,ストリームを閉じ次のノードに転送する. これはサーキットの構築時と同様に,逐次的に行うことができる.
A はサーキット上のある OR に relay truncate cell を送ると,その OR はその先のノードに destroy cell を送り,サーキットを削除する.
- ストリームの開始
アプリケーションが与えられたアドレスとポート番号で TCP接続を求めている場合,接続を OP A に要求する (SOCKS経由).OP は,最新のオープン状態のサーキットを選択 (必要なら生成) し,サーキット上の出口ノードになる適切な OR を選択する. OP は,出口ノードに向け relay begin cell を新しいランダムな streamID を用いて送ることにより,ストリームを開始する.
ユーザの OP A が目的のサイト B とデータの送受信する手順を示す (2つの OR を経由する場合).
- A は,送信データをセッション鍵 K2,K1 の順で多重に暗号化し,最初の中継ノード OR1 に送信する.
A → OR1 : Relay c1 {{Begin, <website>:80}}
- 中継ノード OR1 は,A から受信したデータをセッション鍵 K1 により復号する.このとき,データの次の宛先ノードが判明する.
OR1 は復号した (K2 で暗号化された) データを次の宛先ノード OR2 に中継する.
OR1 → OR2 : Relay c2 {Begin <website>:80}
- 中継ノード OR2 も同様にセッション鍵 K2 でデータを復号すると,最終宛先サーバ B の IPアドレス,ポート番号が判明し,OR2 から サーバ B にアクセスが行われる.
OR2 ←→ B : (TCP hamdshake)
サーバ B からの接続確認レスポンスは,各中継ノードにおいてセッション鍵で暗号化しながら中継し,最終的に A に 2重に暗号化されたデータが渡される.
OR2 → OR1 : Relay c2 {Connected}
OR1 → A : Relay c1 {{Connected}}
A は,受信データをセッション鍵 K1,K2 の順で復号する.
- データの送受信は,上記の手順を繰り返すことにより行われる.
A → OR1 : Relay c1 {{Data, "HTTP GET..."}}
OR1 → OR2 : Relay c2 {Data, "HTTP GET..."}
OR2 → B : "HTTP GET..."
B → OR2 : (response)
OR2 → OR1 : Relay c2 {Data, (response)}
OR1 → A : Relay c1 {{Data, (response)}}