Tor 洋葱路由 — 让你的网络请求穿上三层马甲
是什么
Tor 是一个让你上网时别人看不出你在和谁说话的匿名通信系统。日常类比:像寄一封套了三层信封的信——每个邮局只知道”这封信从哪来、下一站送哪”,没人能同时看到寄件人和收件人。
你的请求在发出去之前,会被套上三层加密,依次经过三个中继节点(叫 Onion Router,简称 OR)。每一跳只剥掉自己那层”外皮”,看到下一站地址,然后把里面的信封原封不动传下去。最后一跳(出口节点)才和真正的目标服务器通信,但它不知道请求最初从哪里来。
这个”第二代”洋葱路由相比 1996 年的原始版本,最关键的改进是:每跳单独协商密钥(telescoping path-building),所以就算某个节点事后被攻破,已发送的流量也无法被解密。这个属性叫完美前向保密:密钥用完就丢,攻击者拿到节点机器后无法回放录下的加密流量。
为什么重要
不理解 Tor,下面这些事都没法解释:
- 为什么中继节点被警方控制后,旧流量仍然无法被还原解密
- 为什么
.onion域名能隐藏服务器 IP,让服务器和客户端互相匿名 - 为什么 Tor 的匿名是概率性的,而不是绝对安全——时序攻击是它的死穴
- 为什么 BitTorrent、VPN 和 Tor 的匿名级别根本不是一回事
核心要点
-
增量式电路构建(telescoping path-building):Alice 不是一次性生成三层加密洋葱再发出去,而是先和第一跳 Bob 协商密钥,再通过 Bob 转发握手报文和第二跳 Carol 协商,以此类推。类比:每挖一段隧道才雇下一个挖掘工,前面的工人不知道整条隧道的长度。密钥协商用的是 Diffie-Hellman 算法——可以理解成两人各自拿一桶颜料往同一个水池里倒,混出的颜色只有他俩能预测,旁观者即使看到水池颜色也猜不出各自拿的是什么颜色的颜料。每跳密钥一旦删除,事后就算节点被攻破也无法解密旧流量(即完美前向保密)。
-
固定长度单元(cell)+ 多路复用:所有流量被分成 512 字节的固定单元,多条 TCP 流共享同一条电路。类比:把不同的信件裁成统一大小的纸张,装进同一个信封——让旁观者无法通过包体大小猜出内容类型。同时用 AES-128 计数器模式加解密,端到端用 SHA-1 摘要做完整性校验,防止中间节点篡改单元内容。
-
会面点(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 秒内完成。
踩过的坑
-
时序攻击(end-to-end timing correlation)是死穴:能同时观察电路两端的攻击者,通过对比流量时序和体积,可以高概率确认通信双方。Tor 设计文档明确声明不防御此类攻击——所以用 Tor 做高风险操作时,对手是否能观测两端至关重要。
-
DNS 泄漏暴露目标地址:应用层(如早期 SSH)若在本地先做 DNS 解析再把 IP 传给 Tor 客户端,DNS 查询会直接发往公共 DNS 服务器,暴露目标域名。必须配合 Privoxy 等过滤代理,或使用支持 SOCKS5h(主机名转发)的工具。
-
出口节点背锅风险:出口节点向目标服务器发出的流量,IP 地址就是出口节点自己的。目标服务器、法律机构、滥用投诉都会指向出口节点运营者,而不是真正的发起人。因此大部分志愿节点选择屏蔽 SMTP 等高风险端口。
-
目录服务器中心化是规模瓶颈:早期只有 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 个增长到数千个,成为全球最大的匿名通信基础设施,也成为隐私研究和审查对抗的标准实验平台。
学到什么
-
匿名性与性能是根本矛盾:每多一跳,延迟多一段传播时延 + 加解密开销。Tor 选择”够用的匿名 + 可接受的延迟”,高延迟系统(Mixmaster)选择”更强的匿名 + 不可用的延迟”,两种取舍服务完全不同的用户。
-
前向保密要靠密钥设计,不是运气:增量式 DH 握手让每跳会话密钥完全独立,节点被攻破后无法追溯旧流量。这是对”先记录、后解密”攻击最直接的防御。
-
实用系统必须与现实妥协:Tor 不做流量填充、不做混合(padding/mixing),因为代价太高且当时没有成熟方案。这份诚实的”非目标”列表(non-goals),比很多论文宣称能解决一切的摘要更有价值。
-
志愿者基础设施的政治学:出口策略、匿名集合大小、滥用风险——每一条都是工程决策,同时也是社会决策。技术系统能否存活,取决于能否给运营志愿者足够的保护。
延伸阅读
- 原始论文 PDF:Tor: The Second-Generation Onion Router (USENIX 2004)
- 官方设计规范:Tor Protocol Specification(比论文更新,细节完整)
- 视频:Roger Dingledine — How Tor Works (DEF CON 22)(作者本人讲解,40 分钟)
- aes —— Tor 电路加密的底层原语,AES-128 计数器模式
- cryptoverif-2008 —— 对握手协议做形式化验证的工具,可用于分析 Tor 的 DH 扩展协议
- bittorrent-2003 —— 同年发布的 P2P 协议,对比:BitTorrent 优化吞吐量,Tor 优化匿名性,两者目标截然相反
关联
- 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 用分布式洋葱节点提升匿名性——都是覆盖网络,目标不同
反向链接
- akamai-2002 —— Akamai 2002 — 把网站搬到离用户 10 毫秒的地方
- amplification-hell-2014 —— Amplification Hell 2014 — 把家用宽带放大成几百 Gbps 的反射攻击
- bittorrent-2003 —— BitTorrent — 用”以牙还牙”逼大家都上传
- chaum-1981-mix —— Chaum Mix Network — 把匿名通信从理论变成工程
- cryptoverif-2008 —— CryptoVerif — 让计算机直接证密码协议在真实计算模型下安全
- danezis-sphinx-2009 —— Sphinx — mix 网络最紧凑的可证安全消息格式
- dingledine-mixminion-2003 —— Mixminion 2003 — 让回复消息和发送消息共享同一张匿名面罩
- dwork-dp-icalp-2006 —— 差分隐私 — ε 与邻接数据集不可区分
- piotrowska-loopix-2017 —— Loopix — 低延迟 mix 网络实现发送方和接收方双向匿名
- reed-onion-routing-1998 —— 洋葱路由 1998 — 把匿名通信从理论搬进真实互联网
- wireguard-2017 —— WireGuard: Next Generation Kernel Network Tunnel