跳转到内容

洋葱路由 1998 — 把匿名通信从理论搬进真实互联网

是什么

洋葱路由(Onion Routing)是一套在公共互联网上建立既防窃听、又防流量分析的匿名 socket 连接的基础设施。日常类比:寄一封信,但外面套了五个密封信封,每个驿站只知道”把最外层信封拆了、把里面的包裹送给下一站”,没有人同时知道发件人和收件人。

你的请求从桌面出发时,被洋葱代理包进一颗”洋葱”——由 RSA 公钥分层加密的数据结构。经过若干台洋葱路由器,每台只剥一层、只知道前驻和后驻,最终由出口漏斗发往真正的服务器。全程任何一个路由器都无法同时看到”谁在跟谁通信”,流量到每一跳都长得不一样。

这篇 1998 年 IEEE JSAC 论文由美国海军研究实验室(NRL)的 Reed、Syverson、Goldschlag 撰写,是 Tor 的直接前身和设计蓝图。

为什么重要

不理解洋葱路由,下面这些事都没法解释:

  • 为什么 Tor 加密后流量仍然可能被关联——论文 §4 告诉你流量分析不等于窃听,是另一个独立威胁
  • 为什么匿名系统要”越忙越安全”——空网络下旁观者可以轻松关联流量突变
  • 为什么 VPN 不等于匿名——VPN 只加密内容,不隐藏”谁在和谁通信”这个元数据
  • 为什么 Tor 用三跳而非两跳——每增加一个诚实节点,攻击者需要同时控制首尾两端才能关联

核心要点

洋葱路由的运作可以拆成三个机制:

  1. 洋葱数据结构:连接建立时,发起端洋葱代理从内到外逐层构造——最内层是目的地,每向外一层用对应路由器的 RSA 公钥加密,并附带密钥种子材料。路由器收到洋葱后,用私钥解密最外层,取出”下一跳地址 + 前向/后向对称密钥种子”,将剩余部分随机填充至原长后转发。任何一层对其他层都是密文。

  2. 分层对称加密传输:连接建立后数据通过固定长度 cell(与 ATM 规格对齐)传输。前向数据经洋葱代理叠加 N 层对称加密(DES OFB / RC4),每经过一个路由器剥一层;回程数据则逐节点加层,由洋葱代理最终解出明文。这保证连接”强度等于最强的一跳”——哪怕其他节点全部受损,只要有一个诚实节点流量就无法被穿透关联。

  3. 代理架构分离应用与匿名层:应用代理负责格式适配(HTTP/SMTP/RLOGIN)和隐私过滤(剥去 Referer / Cookie 等标识头);洋葱代理负责构建洋葱和管理密钥流;入口漏斗将多路匿名连接复用到长驻 socket 上。普通代理感知应用(如浏览器)无需任何修改。

实践案例

案例 1:结合 tor-2004 理解第一代→第二代的演进

想象每次建连就像从旅行社预定路线:1998 年的洋葱路由是”出发前打印好完整地图”,Tor 是”每到一个城市再问当地导游下一站”。前者拓扑固定、公钥静态分发;后者每跳增量协商密钥,任何人随时加入/退出网络。

把本文和 tor-2004 并排阅读,可以精准找到 Tor 解决了哪些 1998 年已知未解的问题:

1998 洋葱路由Tor (2004)
路由固定在建连时确定(静态路由)电路构建协议(circuit-level),每跳增量协商密钥
无完美前向保密(RSA 一次性)DH/椭圆曲线密钥交换,会话密钥独立
拓扑静态、需带外分发公钥目录服务器(Directory Authority)自动同步
只有 5 层洋葱(原型)3 跳(经验证的最小实用跳数)
DESTROY 消息泄漏路由关联改为电路销毁协议,延迟随机化

1998 版坦然承认后两个问题”没有好的解法”——这种学术诚实恰是追溯设计动机的最好文本。

案例 2:用 Python 写一个最小洋葱加解密 demo

先理解对称加密的本质:RC4 / DES OFB 是流密码——把一个密钥扩展成和数据等长的伪随机字节流(keystream),再对数据逐字节 XOR(异或)。因为 XOR 两次等于没做(a ^ k ^ k == a),加密和解密是完全对称的同一操作。

下面演示”三跳洋葱”——建连后数据如何在每个路由器剥一层加密:

import os
def make_key():
return os.urandom(16) # 128-bit 密钥种子
def make_keystream(key: bytes, length: int) -> bytes:
# 把密钥重复扩展到 length 字节(实际用 RC4/DES OFB,这里简化演示)
repeated = (key * (length // len(key) + 1))[:length]
return bytes(k ^ 0xAA for k in repeated) # 模拟流密码输出
def xor_layer(data: bytes, key: bytes) -> bytes:
"""加一层或剥一层——对称操作,两次 XOR 等于还原"""
ks = make_keystream(key, len(data))
return bytes(a ^ b for a, b in zip(data, ks))
# 洋葱代理叠加 3 层:从内到外,最外层对应路由器 1
keys = [make_key() for _ in range(3)]
plaintext = b"GET /index.html HTTP/1.0"
onion_data = plaintext
for key in reversed(keys): # 先加路由器 3 层,再加 2,最后加 1
onion_data = xor_layer(onion_data, key)
# 每个路由器剥一层(与加密完全相同的操作)
for i, key in enumerate(keys):
onion_data = xor_layer(onion_data, key)
print(f"路由器 {i+1} 剥层后: {onion_data[:8]}...")
print("出口漏斗收到:", onion_data) # == plaintext
assert onion_data == plaintext

实际实现中密钥种子经三次 SHA 哈希生成三条密钥(前向 key2 / 后向 key3 / 反重放验证 key1);流密码有内部状态,每过一个 cell 状态推进,所以重放的 cell 会产生不同输出,无法被追踪。

案例 3:把威胁模型当安全分析的学习框架

本文 §4 的威胁模型结构是经典的四象限分析,可以直接套用到任何隐私系统的设计评估中:

被动(只观测) 主动(可修改)
外部攻击者 marker attack 流量注入放大噪声
timing attack 削减流量使关联更容易
——如果网络足够忙则不可行——
内部攻击者 volume attack 强制特定计时签名
(受损节点)timing 广播关联 选择性限速暴露路由
——需要至少 2 个受损节点才能关联——

用日常语言说:外部攻击者好比站在街道上拍照——只能看到流量的形状和时间,但信封是密封的;内部受损路由器好比邮差拆包检查——能看到这一段的内容,但不知道包裹从哪来、要去哪。洋葱路由的设计逻辑是:即便邮差坏了,也需要首尾两端同时坏才能把”谁在和谁通信”拼出来

关键结论:流量匿名性是统计问题,不是密码学问题。密码只解决内容保密;抗流量分析需要流量混淆(固定大小 cell、PADDING 注入、cell 随机重排)。

踩过的坑

  1. 把 VPN 当匿名:VPN 加密了载荷,但你到 VPN 服务器的流量和 VPN 服务器到目的地的流量仍可被外部观测者关联。洋葱路由的核心价值正是让中间每一跳都无法拼出”谁在和谁通信”的完整图景。

  2. DESTROY 消息侧信道:长驻 socket 断开时,所有经过该连接的匿名连接同时收到 DESTROY cell,几乎同时到达多个路由器。受损节点只需比较”哪些连接几乎同时销毁”即可推断它们有公共路径。论文承认暂无好的解法。

  3. 静态拓扑无法扩展:1998 年原型要求所有参与者的公钥和拓扑关系预先配置。在 Tor 出现之前,这是阻止洋葱路由大规模部署的主要工程障碍。没有目录服务器,节点加入或退出需要手动更新所有参与方的配置。

  4. 逐包建洋葱代价极高:对每个 IP 包单独构建一颗洋葱(RSA 解密 × 每跳 × 每包)在 1998 年硬件上远超实时预算。正确的做法是在连接粒度建一条匿名信道,然后在其上承载多路 socket 连接。

适用 vs 不适用场景

适用

  • 需要对网络观测者隐藏”谁在和谁通信”的元数据(新闻记者、维权人士、情报通信)
  • 抗流量分析的 VPN 替代:两个机构之间的通信需要隐藏协作关系
  • 任何基于 TCP socket 的应用,通过应用代理接入,无需修改客户端
  • 研究流量匿名性的基准系统:论文提供了完整的 cell 格式和协议规范

不适用

  • 实时语音/视频:建连延迟(~0.5 秒)+ 多跳 RTT 使延迟不可接受,WebRTC 类方案更合适
  • 高吞吐场景:固定大小 cell + 多层加解密对带宽和 CPU 消耗显著,不适合大文件传输
  • 对抗全局主动攻击者:如果攻击者能同时监控并主动干扰所有出入流量,洋葱路由失效——可参考 chaum-1981-mix 的批量消息混合思路,或 DC-Net 等更激进的方案

历史小故事(可跳过)

  • 1981 年:David Chaum 在 CACM 发表 Mix Networks 论文(chaum-1981-mix),提出通过”混合节点”对消息重排序来抵抗流量分析。但 Mix 假设批量异步消息,不支持实时双向 socket 连接。
  • 1995–1996 年:NRL 的 Syverson、Reed、Goldschlag 开始设计洋葱路由,将 Mix 的分层加密思想移植到 TCP socket 语义。1996 年在”信息隐藏”研讨会发表初稿,同年建成首个原型。
  • 1997 年:IEEE 安全与隐私研讨会上发表会议版论文,NRL 开放了 13 节点真实部署网络(政府、学术界、私人站点各若干)。
  • 1998 年:IEEE JSAC 正式刊发完整规范论文,包含 cell 格式、洋葱层 bit 定义、代理协议状态机。这是 Tor 设计者直接引用的版本。
  • 2002–2004 年:Roger Dingledine(EFF 资助)和 Nick Mathewson 加入 Syverson,将静态拓扑改为目录服务器,引入完美前向保密和三跳默认路由,发布 Tor——将日活用户从十几台节点扩展到今天的数百万规模。

学到什么

  1. 匿名 ≠ 加密:加密保护内容,匿名保护通信模式。两者是正交的需求,洋葱路由同时解决两者,但大多数系统只解决其中一个
  2. 分层抽象隔离安全职责:代理层负责应用适配、洋葱层负责路由匿名、链路层负责链路加密——每一层只做一件事,安全分析边界清晰
  3. 网络越忙越安全:匿名系统的有效性是统计性质——当流量足够多时,被动攻击者无法从大量连接中找出特定会话;正确的工程决策是把多种应用合并共享同一套匿名基础设施
  4. 明确承认未解问题是优秀论文的标志:本文在 §6 列出 DESTROY 泄漏、网络局部断裂两个已知漏洞并坦言没有好解法——这种诚实比”我们解决了一切”更有学术价值,也让后续研究有明确的起点

延伸阅读

  • 原文 PDF:Reed et al. 1998, IEEE JSAC(完整协议规范,尤其看 §5 的 cell 格式和洋葱层结构)
  • tor-2004 —— 直接读第二代设计,对比本文哪些问题被解决、哪些仍是 open problem
  • chaum-1981-mix —— Mix Networks 原始论文,洋葱路由的密码学思想来源
  • Dingledine et al., “Tor: The Second-Generation Onion Router”(2004 USENIX Security)—— 与本文并排阅读

关联

  • tor-2004 —— Tor 是洋葱路由的第二代实现,直接继承并修复了本文遗留的未解问题
  • chaum-1981-mix —— Chaum 1981 Mix Networks 是洋葱路由分层加密思想的直接来源;本文 §8 详细对比了两者的异同
  • libsignal —— 端到端加密的代表实现;与洋葱路由互补——Signal 加密内容,洋葱路由加密连接元数据

反向链接

  • chaum-1981-mix —— Chaum Mix Network — 把匿名通信从理论变成工程
  • libsignal —— libsignal — 端到端加密的 Rust 内核
  • piotrowska-loopix-2017 —— Loopix — 低延迟 mix 网络实现发送方和接收方双向匿名
  • tor-2004 —— Tor 洋葱路由 — 让你的网络请求穿上三层马甲