钱包说走了 Tor,DNS 却漏了:四个钱包的 SOCKS5 实测
四款钱包,同一次 SOCKS5 握手:Electrum、Sparrow、Feather、Monero GUI 谁把主机名交给代理,谁在本地解析,附五个可自查的检查。
钱包上的 Tor 开关,是对它发出的每一个数据包的承诺;而承诺最容易验证的地方,恰好是它真正做决定的那一行:SOCKS5 请求。这篇审计读四个钱包——Electrum、Sparrow、Feather、Monero GUI——用一个会记录目标地址的 SOCKS5 代理把差别量出来。结论不是「Tor 有用」或「Tor 没用」,而是一张地图:四个里有三个在默认路径上把服务器名交给代理,而每一个都有一处明确的绕行点。这些在界面上全都看不见,所以本文末尾的检查比那个开关更重要。 (Tor 换币安全吗)
一个字节决定谁来解析。 SOCKS5 在请求的 ATYP 字段里写目标:0x01 是 IPv4 字面量,0x03 是域名。发 0x03,解析发生在代理——也就是 Tor 那一侧;发 0x01,说明你的机器已经解析过了,那条查询在隧道建立之前就已经出去了。我在 127.0.0.1:1081 起了一个会记日志的 SOCKS5 监听,用 curl 对同一个目标发了两次:`curl --socks5` 记到 `ATYP=1 HOST=172.66.147.243:80`;`curl --socks5-hostname` 记到 `ATYP=3 HOST=example.com:80`。同一个代理、同一个目标,差别只有一处:第一种情况下,DNS 答案在 Tor 参与之前就已经存在了。下面每个钱包在代码里做的都是这个选择,而且从不告诉你。 (Tor 换币安全吗)
Electrum:它会主动探测,而且探得很严。 在未配置代理(出厂默认就是没有代理)的情况下,Electrum 会并行探测 127.0.0.1 的 9050、9051、9150 三个端口来发现本地 Tor。这个探测不是简单的 TCP 连接,而是发一个 18 字节的 SOCKS5 握手,末尾是命令 0xF0——Tor 的 RESOLVE 扩展——目标是 0.0.0.0,并且只接受一字不差的 12 字节回复 `05 00 05 00 00 01 00 00 00 00 00 00`。我把源码里的字节发给自己的模拟器,日志是 `CMD=0xf0 ATYP=3 HOST=0.0.0.0:0`,正是 Tor 会回的形状。由此有两个实际后果:不实现 RESOLVE 的通用 SOCKS5(ssh -D、dante)通不过探测,Electrum 就此保持直连——不报错、不提示;另外 9051 是 Tor 的控制端口,三个探测里注定有一个是死的。 (Tor 换币安全吗)
在真的走代理的情况下,Electrum 的主路径是干净的:它的 SOCKS 层把主机名编码成 ATYP 0x03,服务器名以未解析形态抵达代理。例外藏在同一个仓库里。`dnssec.py` 向硬编码的 8.8.8.8 解析,源码注释写着「FIXME this method is not using the network proxy」,而 `contacts.py` 会调它去查支付标识符。也就是说,你用 name@domain 这种标识符时,那条 DNS 查询是你这台机器明文发出去的——尽管 Tor 在跑、代理已开。这是一条窄路径,不是区块链连接,但泄漏身份这种事的,往往正是窄路径。 (Tor 换币安全吗)
Sparrow:两条传输通道,两个相反的答案。 同一个应用,取决于你选的服务器协议,行为完全不同。SSL(50002 端口)加代理时,Sparrow 走 `ProxyTcpOverTlsTransport`,它的连接调用是 `InetSocketAddress.createUnresolved(server.getHost(), port)`:主机名交给 SOCKS 代理,本地解析器完全不会被问到。而明文 TCP(50001 端口)加代理时,它退回 `TcpTransport` 加 `ProxySocketFactory`,那里 `createAddress` 只对 .onion 主机保持未解析;明文主机走 `new InetSocketAddress(address, port)`,构造函数里就解析完了——发到 Tor 的是 IP,不是名字。Sparrow 默认的公共服务器用 SSL,所以常见配置是安全的那条;例外离你只有服务器列表里的一次点击。 (Tor 换币安全吗)
Feather:默认是 Tor,但首次同步除外。 Feather 出厂就把 proxy 设为 Tor,并用 `--SocksPort 127.0.0.1:19450` 启动自带的 tor 二进制。缺口在隐私级别上:默认值就是「除首次同步外全部走 Tor」,而决定是否挂代理的那个函数在 Tor 模式下返回的是「只用 onion 节点」——这个条件在钱包完成一次刷新之前(或链高没到初始同步阈值之内)一直是 false。翻译过来:首次同步这一波钱包一生中最大、最有特征的流量,是直接连明文节点的。同步完成后代理才生效;开了「仅 onion」之后才走 .onion 节点,并且刻意关掉 TLS,因为那一跳已经由 Tor 加密了。 (Tor 换币安全吗)
Monero GUI:一个开关,管得比你想的宽。 GUI 接受 `--socks5-proxy address:port`,它自己的源码写明覆盖「远程节点连接、更新下载、以及价格源抓取」。钱包自身的 `--proxy` 参数更窄——只给守护进程连接用的 socks 代理——而底层的 SOCKS 客户端构造的是 `v5_domain_connect` 请求,ATYP 0x03,所以守护进程的主机名进了代理,而不是进了你的解析器。两个推论:这个设置是通用 SOCKS5,不是 Tor 开关,指向非 Tor 代理只是多一跳、匿名性为零;另外它的作用域包含更新检查和价格查询,也就是说你广播交易的同时,同一个电路上还会有一个请求打到第三方价格 API。 (Tor 换币安全吗)
ATYP 正确也不等于隐身。 全部用 0x03 之后,本地解析器确实出局了,但出口节点仍然看得见目标主机名,明文 TLS 下还看得见 SNI。只有 .onion 节点能同时消掉这两样:没有 DNS 查询,也没有主机名可读。两种情况都还在的是时间——钱包连上节点之后没过多久交易就出现,这种相关性,一个同时看两边的观察者是可以去试的。Tor 挪动的是观察点,不是删掉观察。谁说「打开 Tor 开关链上转账就隐私了」,那是在卖一个不存在的东西。 (Tor 换币安全吗)
十分钟能做完的五个检查。(1)钱包空闲时跑 `ss -tnp`,不应该出现不属于 tor 进程的 50001、50002、18081、18089 出站连接。(2)跑 `sudo tcpdump -ni any udp port 53` 再重启钱包,打印出来的每一条查询,都是没进隧道的解析。(3)把系统解析器指向 127.0.0.1 这种黑洞地址再重启:钱包还能连上,说明它本来就不本地解析;连不上,说明它一直在本地解析。(4)在 Electrum 里,把 `--proxy socks5:127.0.0.1:9050` 和一个非 Tor 的 SOCKS 服务器对比,看自动探测怎么拒绝后者。(5)在 Sparrow 里,代理开着,把同一个服务器在 50001 和 50002 之间切换,看哪一个会触发 DNS 查询。 (Tor 换币安全吗)
这对一次兑换意味着什么,以及它修不好什么。 往入金地址发币,全程不需要任何 DNS 查询:你粘一串字符、签名。真出问题的地方,是钱包和它的节点之间那条连接,而那条连接在下单前后一直存在。把这两件事分开看。订单页的职责是不记录你——本站有 Tor 镜像 4jyoxqdyx7dh3xfjctihpld7fgliowhimajfszcgypxash5rjqhas3yd.onion,也不要账户。钱包的职责是不暴露你。截至 2026-11-06 10:05 UTC 的实测:100 USDT-TRON 报 0.1420618 XMR,隐含 703.9 美元/XMR,现货 617.43;1 XMR 反向报 612.157 USDT,走 2 条路由。小额端的差价是锁价路线,不是隐私附加费,实时报价为准。SOCKS5 审计给你的东西更小也更实用:你知道钱包设置里那个「Tor」,描述的是一个请求里的一个字节——而且你可以亲自去看。 (Tor 换币安全吗)