onion 服务到底是什么
Tor onion 服务是一种只能通过 Tor 网络访问的服务器,其地址以 .onion 结尾,并且由一个加密密钥推导而来,而不是由注册商分配。这里没有 DNS 查询,没有任何记录中的公网 IP,也没有需要购买的 TLS 证书:这个 56 个字符的地址本身就是该服务的公钥,因此连接从构造上就是经过身份验证、端到端加密的。运行 Tor Browser 的访问者输入这个地址;网络会安排一个加密的会合点;双方进行通信,但谁也无法得知对方的位置。中间没有任何一方——无论是中继节点、ISP,还是托管服务商——能同时看到对话的两端。
对托管而言,真正重要的后果是结构性的,而不是表面的。普通的 Web 服务器必须在公网端口上监听,这意味着它的地址可被发现、可被扫描,并最终可以关联到付账的人。onion 服务则不在任何互联网可达的地方监听。机器上的 Tor 只发起出站连接,与少数几个介绍点建立电路,然后等待。这项服务在线并正在处理流量,与此同时 ss -tlnp 却显示没有任何东西绑定在可路由的地址上。这种反转,正是运行 onion 服务的全部意义所在。
什么时候该用它——什么时候不该用它
当机器所在的位置本身就是你要保护的一部分时,就该选择 onion 服务:一个即便明网域名被查封也必须保持可访问的网站、一个供线人或研究者提交材料的信箱、一个你根本不想让它暴露在扫描流量之下的管理面板,或者一项受众本就已经在使用 Tor、并且看重你根本收不到、因而也无法记录其 IP 这一点的服务。当“隐藏源”才是真正的需求时,onion 服务同样是老实的答案——摆在明网服务器前面的反向代理只会转移目标,而 onion 服务则将其彻底消除。
但如果你的访问者不会、也不能运行 Tor,如果你需要一台可直接访问的服务器才有的原始吞吐量和低于 100 毫秒的延迟,或者如果重点就在于能被发现——onion 地址可不是人们从搜索引擎里随便就能碰到的东西。许多运营者会两者兼顾,同时运行两个版本:一个面向大众访问的普通网站,一个面向想要它的用户的 onion 服务,背后是同一个应用。我们会在下文介绍这种模式。不过,这里的任何内容都不能替代对机器本身的加固;一旦机器被攻陷,无论它是以什么方式发布的,其位置和内容都会泄露,所以要把第一小时加固清单当作前提条件,而不是事后才想起来的补救。
SP·03这套方案暴露了什么,又是暴露给谁
有必要把这套匿名模型说清楚,因为人们常常想当然地认为“onion 服务”就等于“无法追踪”,而实际情况要具体得多。客户端永远无法得知服务器的 IP 地址——这一属性非常可靠,也正是重点所在。然而,你的托管服务商依然能看到自己网络里有一台机器,正持续不断地向 Tor 网络发起加密出站连接;他们看不到 onion 地址、看不到内容,也看不到访问者,但能看到这台机器在讲 Tor 协议。在一台与你身份绑定的主流主机上,这就是一条值得深挖的线索。而在一台离岸、匿名付款、没有登记任何姓名的 VPS 上,这条线索哪儿也通不到——这正是这两项技术应该搭配使用的原因。
真正会让 onion 服务失去匿名性的失败模式,几乎从来都不是 Tor 本身的问题。而是应用在错误页面、某个响应头、它发出的邮件,或者一个访问明网分析或更新端点的出站请求中泄露了真实 IP;是配置有误的服务器暴露了自己的主机名或时区;又或者是运营者在明网身份中反复使用同一台机器、同一把密钥或同一种写作风格所造成的关联。密码学本身是牢靠的;真正让人栽跟头的,是围绕它的这些管线。下面的每一步都是为了让这些管线保持严密而写的——绑定到本地回环地址、不以明文方式向外发送任何东西,并且按照不让服务器留下你的名字里的做法,把这台机器的真实身份撇干净。
SP·04安装最新版 Tor,而不是发行版自带的那个
发行版会把 Tor 锁定在发布时所带的那个版本上,而 onion 服务的防护手段更新很快——介绍点拒绝服务防护、v3 客户端授权,以及好几个稳定性修复,全都出现在比稳定版 Debian 或 Ubuntu 默认自带版本更新的版本里。请从 Tor Project 自己的签名软件源安装,这样你跟随的就是最新发布节奏,安全更新也按他们的节奏推送,而不是按发行版的节奏。下面这段代码会自动识别你的发行版代号,并把软件源绑定到该项目的签名密钥上,这样即便有攻击者篡改镜像,也无法给你塞进一个被降级的软件包。
在 Debian 和 Ubuntu 上,Tor 以无特权的 debian-tor 用户身份运行,会进入沙箱,也不需要任何特殊的网络权限——它只是像普通客户端一样拨出连接。onion 服务本身不需要在防火墙上开放任何东西,这是整个过程里第一个令人愉快的惊喜:你的默认拒绝防火墙可以保持原来那么严格,一点都不用放松。
把应用绑定到本地回环地址,其他地方都不绑定
onion 服务只是架在一个普通本地服务前面的一道门——可以是 Web 服务器、应用、SSH 守护进程,任何讲 TCP 的东西都行。让整套方案保持安全的规则是:这个本地服务必须只监听回环接口,也就是 127.0.0.1。如果它同时也监听公网 IP,你就悄悄地把 onion 服务原本要解决的问题又重新制造了出来:内容现在可以被直接访问、被指纹识别,而一次把你的明网服务器和 onion 内容对上号的扫描,一次请求就能让匿名性化为乌有。绑定到回环地址,用 ss -tlnp 确认,让 Tor 成为唯一能连上这个端口的东西。
由于 Tor 和你的应用之间的流量始终停留在 127.0.0.1 上,它从不接触网络,也就不需要自己的 TLS——Tor 电路本身已经做了端到端加密。不要在回环监听端口上放一张自签名证书;那只会多出一个可被指纹识别的特征,却什么好处都换不来。让这个应用保持无聊:不做明网跳转、模板里不要写死 https://your-domain 这种绝对链接,也不要引入第三方字体或分析脚本,以免让访问者的浏览器跳出 onion,连到公开的 Web 上去。
声明这项服务,然后读取你的地址
onion 服务只需要 torrc 里的三行配置:一个 Tor 存放密钥材料的目录,以及一条从 onion 地址上的虚拟端口到你应用所监听的本地端口的映射。第一次重启时,Tor 会在这个目录里生成一个 Ed25519 密钥对,并写出 hostname 文件——也就是你要对外公布的那个 56 个字符的 .onion 地址。只要密钥还在,这个地址就是永久的。丢了密钥,地址就永远消失;泄露了密钥,别人就能冒充你的服务。把 HiddenServiceDir 当作皇冠上的明珠来对待:权限设为 0700,属主是 Tor 用户,并且要有一份经过加密、存放在机器之外的备份。
除了这条映射之外,还有两个设置值得加上。HiddenServiceEnableIntroDoSDefense 1 能让你的介绍点在连接洪水抵达你的机器之前先做速率限制,这是 onion 服务能获得的、最接近 DDoS 防护的手段。锁定 HiddenServiceVersion 3 能让版本明确下来,并且面向未来。如果这项服务应该是私有的而不是公开的,v3 客户端授权可以把访问范围限制在持有你带外分发的密钥的人手里——这是运行一个管理面板的干净做法:没有凭据的人,连回应都得不到。
公布它、双线并行,并选一个好记的地址
如果你同时运营着一个明网网站,可以通过 Onion-Location 响应头(或者等价的 HTML meta 标签)告诉 Tor Browser 对应的 onion 版本在哪里。支持 onion 的浏览器随后会自动向访问者提供这个 .onion 地址——这正是各大报社和搜索引擎网站展示自己 onion 版本的标准做法。让同一个应用同时挂在一个域名和一个 onion 地址上,是常态,而不是什么特例:同一套代码库、同一个数据库、两扇门,明网那一侧照常放在隐藏源 IP 的反向代理后面,onion 那一侧则什么都不暴露。
默认地址是一串随机的 56 个字符,安全,但不好记。靓号地址可以让你通过暴力破解,得到一个 base32 编码以指定前缀开头的密钥——几个可读字符很快就能跑出来,但每多一个字符,工作量就要乘以 32,所以一旦超过七八个字母,就会变成一项相当吃算力的工作。请在一台受信任的本地机器上生成靓号密钥,绝不要在服务器上生成,然后把生成出来的密钥像还原备份一样放进 HiddenServiceDir。一个可识别的前缀,还能挫败一种真实存在的攻击:钓鱼克隆站——它们指望的就是没有人会去读一整墙的随机字符。
让它持续运行:性能、监控与密钥卫生
一次 onion 连接要经过六个中继,而不是通常的零个,所以延迟比直接可达的服务器更高、吞吐量也更低——这是物理限制,不是配置问题,任何设置都消除不了它。不要为了找回速度而去尝试单跳或非匿名模式;那样做换掉的,恰恰是你搭建这一切所追求的那个属性。你真正能做的是:保持 Tor 是最新版本、让介绍点的 DoS 防护保持开启、给繁忙的服务加上缓存以减少每次请求的工作量,并为机器预留足够的 CPU 余量,因为 Tor 的密码学运算不是免费的。一台起价 $8.00/月的普通离岸 VPS,就足以从容应付一个典型的 onion 网站。
在运维层面,有三个习惯能让 onion 服务保持健康。用 journalctl -u tor@default 关注可达性和描述符发布方面的错误,而不要想当然地认为没有输出就等于健康。在创建 HiddenServiceDir 的当天,以及此后每次改动之后都要备份它,并且要加密、存放在机器之外,因为这把密钥是唯一无法重新生成的东西。还要保持机器运维身份的干净——如果同样的操作习惯把它和一个明网身份关联了起来,那么一台全新匿名 VPS 上的一把全新密钥也没多大意义。这项服务完全可以多年不用管、安稳运行;真正需要自律的是围绕它的这些管线,而不是服务本身。
分步操作
-
01
从一台已经加固、匿名的机器开始
部署一台离岸 VPS——大约 15 min 就能上线——先把枯燥但必不可少的基础工作做好:一个具名的 sudo 用户、仅密钥登录的 SSH、一道默认拒绝的防火墙,以及自动安全更新。onion 服务不需要你在这道防火墙上额外开放任何东西,所以一台锁得很紧的机器依然能保持锁紧状态。不要跳过这一步;把 onion 地址架在一台已被攻陷的服务器前面,什么都藏不住。
ssh admin@203.0.113.10 sudo apt update && sudo apt full-upgrade -y # firewall stays default-deny; the onion service needs no inbound port sudo ufw status verbose
-
02
从 Tor Project 的软件源安装 Tor
先添加该项目的签名软件源,这样你运行的就是带有最新 onion 服务防护的当前版 Tor,然后再安装它。发行版代号是从
/etc/os-release中自动识别的,软件源则绑定到 Tor 的签名密钥上,这样即便镜像被篡改,也无法把你降级到旧版本。sudo apt install -y apt-transport-https wget gpg . /etc/os-release wget -qO- https://deb.torproject.org/torproject.org/A3C4F0F979CAA22CDBA8F512EE8CBC9E886DDD89.asc \ | gpg --dearmor | sudo tee /usr/share/keyrings/tor.gpg >/dev/null echo "deb [signed-by=/usr/share/keyrings/tor.gpg] https://deb.torproject.org/torproject.org $VERSION_CODENAME main" \ | sudo tee /etc/apt/sources.list.d/tor.list sudo apt update && sudo apt install -y tor deb.torproject.org-keyring
-
03
把你的服务只绑定到本地回环地址
不管你要发布的是什么,都只把它指向回环接口,别的地方都不要。这里的例子是 nginx 在
127.0.0.1:8080上提供一个静态网站;同样的原则适用于任何应用——绑定到127.0.0.1,而不是0.0.0.0。重新加载之后,用ss证明确实没有任何东西监听在可路由的地址上。# /etc/nginx/sites-available/onion.conf server { listen 127.0.0.1:8080; server_name _; root /var/www/onion; index index.html; }启用它、重新加载,并确认绑定确实只在回环地址上:
sudo ln -s /etc/nginx/sites-available/onion.conf /etc/nginx/sites-enabled/ sudo nginx -t && sudo systemctl reload nginx ss -tlnp | grep 8080 # must show 127.0.0.1:8080, never 0.0.0.0:8080
-
04
在 torrc 里声明这个 onion 服务
把这项服务加进
/etc/tor/torrc:一个密钥目录,以及一条从 onion 地址的虚拟端口 80 到本地 8080 的端口映射。打开介绍点 DoS 防护,并锁定地址版本。然后重启 Tor——在 Debian 和 Ubuntu 上,正在运行的实例是tor@default。# /etc/tor/torrc HiddenServiceDir /var/lib/tor/onion-www/ HiddenServicePort 80 127.0.0.1:8080 HiddenServiceVersion 3 HiddenServiceEnableIntroDoSDefense 1 sudo systemctl restart tor@default
-
05
读取地址并锁死密钥权限
此时 Tor 已经生成好密钥材料并写出了你的地址。把它读出来、公布出去——同时确认这个目录的权限是
0700、属主是 Tor 用户;Tor 本身会强制这一点,但一次粗心的恢复操作可能把它破坏掉。这个目录里的hs_ed25519_secret_key文件就是你的身份;除此之外别无他物。sudo cat /var/lib/tor/onion-www/hostname # example: 2gzyxa5ihm7nsggfxnu52rck2vv4rvmdlkiu3zzui5du4xyclen53wid.onion sudo ls -l /var/lib/tor/onion-www/ # hostname hs_ed25519_public_key hs_ed25519_secret_key sudo chown -R debian-tor:debian-tor /var/lib/tor/onion-www sudo chmod 700 /var/lib/tor/onion-www
-
06
通过 Tor 测试它,然后公布出去
从一台运行着 Tor 的机器上验证这项服务,使用
torsocks让请求走 Tor 网络,而不是明网。等它开始响应之后,你可以选择在自己的常规网站上用一个Onion-Location响应头,把明网访问者指向 onion 版本。# from any box running tor: torsocks curl -sSI http://2gzyxa5ihm7nsggfxnu52rck2vv4rvmdlkiu3zzui5du4xyclen53wid.onion/ | head # advertise the onion from your clearnet nginx (inside the https server block): add_header Onion-Location "http://2gzyxa5ihm7nsggfxnu52rck2vv4rvmdlkiu3zzui5du4xyclen53wid.onion$request_uri";
-
07
备份密钥,并写好运维手册
这个地址与密钥目录同生共死。密钥目录一生成,就立刻把它打包归档,把归档文件转移到机器之外的加密存储中,并且要清楚,把它还原到任何地方都会重现出完全相同的
.onion地址。然后写下六个月后你真正会用到的那两条命令——密钥放在哪里、怎么检查健康状况——因为这项服务会安安静静运行很长时间,长到你一定会忘记。sudo tar czf onion-www-key.tar.gz -C /var/lib/tor onion-www # copy onion-www-key.tar.gz to encrypted off-box storage, then delete the local copy # health check any time: sudo systemctl status tor@default sudo journalctl -u tor@default --since "1 hour ago" | grep -i "onion\|error"


