跳转到内容

Tor 洋葱路由 — 让你的网络请求穿上三层马甲

是什么

Tor 是一个让你上网时别人看不出你在和谁说话的匿名通信系统。日常类比:像寄一封套了三层信封的信——每个邮局只知道”这封信从哪来、下一站送哪”,没人能同时看到寄件人和收件人。

你的请求在发出去之前,会被套上三层加密,依次经过三个中继节点(叫 Onion Router,简称 OR)。每一跳只剥掉自己那层”外皮”,看到下一站地址,然后把里面的信封原封不动传下去。最后一跳(出口节点)才和真正的目标服务器通信,但它不知道请求最初从哪里来。

这个”第二代”洋葱路由相比 1996 年的原始版本,最关键的改进是:每跳单独协商密钥(telescoping path-building),所以就算某个节点事后被攻破,已发送的流量也无法被解密。这个属性叫完美前向保密:密钥用完就丢,攻击者拿到节点机器后无法回放录下的加密流量。

为什么重要

不理解 Tor,下面这些事都没法解释:

  • 为什么中继节点被警方控制后,旧流量仍然无法被还原解密
  • 为什么 .onion 域名能隐藏服务器 IP,让服务器和客户端互相匿名
  • 为什么 Tor 的匿名是概率性的,而不是绝对安全——时序攻击是它的死穴
  • 为什么 BitTorrent、VPN 和 Tor 的匿名级别根本不是一回事

核心要点

  1. 增量式电路构建(telescoping path-building):Alice 不是一次性生成三层加密洋葱再发出去,而是先和第一跳 Bob 协商密钥,再通过 Bob 转发握手报文和第二跳 Carol 协商,以此类推。类比:每挖一段隧道才雇下一个挖掘工,前面的工人不知道整条隧道的长度。密钥协商用的是 Diffie-Hellman 算法——可以理解成两人各自拿一桶颜料往同一个水池里倒,混出的颜色只有他俩能预测,旁观者即使看到水池颜色也猜不出各自拿的是什么颜色的颜料。每跳密钥一旦删除,事后就算节点被攻破也无法解密旧流量(即完美前向保密)。

  2. 固定长度单元(cell)+ 多路复用:所有流量被分成 512 字节的固定单元,多条 TCP 流共享同一条电路。类比:把不同的信件裁成统一大小的纸张,装进同一个信封——让旁观者无法通过包体大小猜出内容类型。同时用 AES-128 计数器模式加解密,端到端用 SHA-1 摘要做完整性校验,防止中间节点篡改单元内容。

  3. 会面点(rendezvous points)与隐藏服务:服务器 Bob 不直接暴露 IP,而是在网络里登记几个”接待员”(introduction points),客户端 Alice 另找一个”会合地点”(rendezvous point),双方通过两条独立电路在会合地点相遇。类比:两个陌生人约在一个谁都不是老板的咖啡馆见面,咖啡馆老板只知道”有两个人今天来了”,不知道他们是谁。这就是 .onion 地址的底层实现。

实践案例

案例 1:三跳电路建立与加解密层剥离

# 伪代码演示:Alice 通过 OR1 → OR2 向目标发送 HTTP 请求
# 增量式握手:Alice 依次和每跳协商 Diffie-Hellman 密钥
keys = []
for hop in [OR1, OR2, OR3]:
# Alice 发送 E(public_key_hop, g^x)
# hop 回复 g^y, H(K | "handshake")
session_key = dh_exchange(hop) # K = g^(xy)
keys.append(session_key)
# 发送时逐层加密(最远的那跳最里层)
payload = b"GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"
for key in reversed(keys): # 从 OR3 到 OR1 逆序加密
payload = aes_ctr_encrypt(key, payload)
# OR1 剥掉第一层 → 转发给 OR2
# OR2 剥掉第二层 → 转发给 OR3
# OR3 剥掉第三层 → 明文发给 example.com

逐部分解释:

  • reversed(keys) 保证 OR3 的密钥最里层,OR1 的最外层
  • 每个 OR 只做一次 AES 解密,不知道还剩几层
  • SHA-1 摘要(取前 4 字节)只有目标 OR 能验证,其他节点解密后摘要不合法,自动往下传

案例 2:隐藏服务的会面流程

Bob(服务器):
1. 生成公私钥对 → 哈希得到 .onion 地址(如 xyz...abc.onion)
2. 建立到 IP1、IP2 的电路,告诉它们"我是 xyz.onion 的接待员"
3. 在目录服务器登记:signed { onion_addr → [IP1, IP2] }
Alice(客户端):
1. 从目录获取 xyz.onion 的接待员列表
2. 选 RP(会合点),建立电路到 RP,发送 rendezvous_cookie
3. 通过 IP1 给 Bob 发消息:{ RP地址, cookie, DH_half_1 },用 Bob 公钥加密
4. Bob 建立电路到 RP,发送 { cookie, DH_half_2, H(session_key) }
5. RP 将两条电路接通 → 匿名双向通信建立

关键点:RP 既不知道 Alice 是谁,也不知道 Bob 在哪里,只知道”两个电路接在一起了”。

案例 3:拥塞控制的 sendme 机制

电路级拥塞控制(简化):
初始 packaging_window = 1000 单元
OR 每转发 1 个 relay data 单元 → packaging_window -= 1
OR 每收到 100 个单元后 → 向 OP 发 relay_sendme(streamID=0)
OP 收到 relay_sendme → packaging_window += 100
如果 packaging_window == 0:
OR 停止从 TCP 连接读取数据
等待下一个 relay_sendme 才恢复

这套机制不需要全局协调,完全靠端到端 ACK 实现。论文实测:同机 4 节点网络下载 60MB 文件约 300 秒,直连 210 秒;生产网络获取 55KB 页面中位延迟 2.8 秒,90% 在 5.3 秒内完成。

踩过的坑

  1. 时序攻击(end-to-end timing correlation)是死穴:能同时观察电路两端的攻击者,通过对比流量时序和体积,可以高概率确认通信双方。Tor 设计文档明确声明不防御此类攻击——所以用 Tor 做高风险操作时,对手是否能观测两端至关重要。

  2. DNS 泄漏暴露目标地址:应用层(如早期 SSH)若在本地先做 DNS 解析再把 IP 传给 Tor 客户端,DNS 查询会直接发往公共 DNS 服务器,暴露目标域名。必须配合 Privoxy 等过滤代理,或使用支持 SOCKS5h(主机名转发)的工具。

  3. 出口节点背锅风险:出口节点向目标服务器发出的流量,IP 地址就是出口节点自己的。目标服务器、法律机构、滥用投诉都会指向出口节点运营者,而不是真正的发起人。因此大部分志愿节点选择屏蔽 SMTP 等高风险端口。

  4. 目录服务器中心化是规模瓶颈:早期只有 3 台目录服务器,每个客户端每 15 分钟下载完整的网络状态描述。节点超过几百台、用户超过万人,这套机制就会遇到带宽和信任瓶颈。论文末尾承认这是未解决的开放问题。

适用 vs 不适用场景

适用

  • 需要对目标服务器隐藏客户端真实 IP 的 TCP 流量(Web 浏览、SSH 等)
  • 隐藏服务(.onion)——让服务器和客户端都匿名
  • 绕过网络审查——出口节点分布在多个司法辖区
  • 研究匿名通信协议的测试平台

不适用

  • UDP 流量(Tor 只支持 TCP,不支持非流式协议)
  • 需要低延迟实时通信(游戏、视频会议)——多跳加解密引入 2-5 秒额外延迟
  • 防御全局被动对手(ISP/政府能观测全网流量)——时序攻击无解
  • 要求匿名性有数学保证的场景——Tor 的匿名是统计概率,非密码学绝对

历史小故事(可跳过)

  • 1981 年:David Chaum 提出 Mix-Net,用洋葱式公钥加密隐藏邮件发送者,是匿名通信的理论源头。
  • 1996 年:美国海军研究实验室的 Goldschlag、Reed、Syverson 发表第一代洋葱路由,但实现是概念验证,单机运行,从未真正部署。
  • 2003 年 10 月:Roger Dingledine 和 Nick Mathewson(Free Haven Project)与 Syverson 合作,部署了第一个真实测试网络,32 个节点分布在美国和欧洲,同年代码以自由软件许可证发布。
  • 2004 年:设计论文在 USENIX Security 发表,测试网络已有几百个真实用户(企业内部流量、记者、活动人士)。
  • 此后:Tor Project 非营利基金会成立,节点从 32 个增长到数千个,成为全球最大的匿名通信基础设施,也成为隐私研究和审查对抗的标准实验平台。

学到什么

  1. 匿名性与性能是根本矛盾:每多一跳,延迟多一段传播时延 + 加解密开销。Tor 选择”够用的匿名 + 可接受的延迟”,高延迟系统(Mixmaster)选择”更强的匿名 + 不可用的延迟”,两种取舍服务完全不同的用户。

  2. 前向保密要靠密钥设计,不是运气:增量式 DH 握手让每跳会话密钥完全独立,节点被攻破后无法追溯旧流量。这是对”先记录、后解密”攻击最直接的防御。

  3. 实用系统必须与现实妥协:Tor 不做流量填充、不做混合(padding/mixing),因为代价太高且当时没有成熟方案。这份诚实的”非目标”列表(non-goals),比很多论文宣称能解决一切的摘要更有价值。

  4. 志愿者基础设施的政治学:出口策略、匿名集合大小、滥用风险——每一条都是工程决策,同时也是社会决策。技术系统能否存活,取决于能否给运营志愿者足够的保护。

延伸阅读

关联

  • aes —— Tor 每个电路单元用 AES-128 计数器模式加解密,性能分析显示 AES 是 CPU 占用主因
  • cryptoverif-2008 —— 可对 Tor 的 DH 握手协议(Alice→Bob: E(PKBob, g^x))做密码学形式化验证
  • bittorrent-2003 —— 同为 2003-2004 年出现的 P2P 网络协议,但设计目标截然相反:效率 vs 匿名性
  • amplification-hell-2014 —— 反射放大攻击:Tor 出口节点也可能被用于流量放大,出口策略需要考虑 UDP 协议风险
  • akamai-2002 —— CDN 用分布式缓存节点提升性能;Tor 用分布式洋葱节点提升匿名性——都是覆盖网络,目标不同

反向链接