你的痕迹是怎么泄露的
泄露很少来自某一个"致命漏洞"。它来自一层层信号叠加出来的相关性——单独看,你的 IP 不特殊、字体不特殊、时区不特殊;合在一起,能唯一指向你的那一个人。
你的痕迹分六层:IP 与 ASN、DNS 解析、WebRTC 候选地址、浏览器与设备指纹、TLS/协议栈指纹、行为与内容特征。其中 IP、DNS、WebRTC 属于"直接暴露真实位置"的硬泄露;指纹与行为属于"不打自招"的软泄露,靠熵值唯一化。真正有效的做法不是逐项伪装,而是让各层之间不矛盾,并接受"降低可关联性"而不是"消失"。
先建立模型:六层痕迹
| 层 | 泄露什么 | 怎么被看到 | 严格程度 |
|---|---|---|---|
| 1 · 网络 | 出口 IP、ASN(住宅/机房/移动)、IPv4/IPv6 双栈 | 任何一次 TCP/TLS 连接的源地址 | 硬泄露 |
| 2 · 名称解析 | 谁在替你解析、你的子网、解析地 vs 出口地 | DNS 查询路径、EDNS Client Subnet | 硬泄露 |
| 3 · UDP / 媒体 | 真实公网 IP、局域网地址、NAT 类型 | WebRTC 的 STUN 与 ICE 候选 | 硬泄露 |
| 4 · 应用与设备 | GPU、字体、Canvas、时区、语言、屏幕、并发数 | 纯 JS API,无需权限 | 软泄露(熵) |
| 5 · 协议栈 | TLS 参数集、HTTP/2 设置、TCP 行为 | 握手阶段的被动特征 | 软泄露(强) |
| 6 · 行为与内容 | 打字节奏、活跃时段、写作风格、账号命名习惯 | 遥测与跨站关联 | 软泄露(最难改) |
前四层是绝大多数人讨论的部分;第五、六层是真正让"换了代理还是被认出来"的原因。逐层往下看。
第一层:IP 与 ASN
IP 不只是"一个地址"。它同时暴露三件事:地理位置(粗到国家,细到城市)、网络属性(ASN 属于住宅宽带、移动运营商还是云机房)、以及你与谁共享这个出口(同一个出口上的所有行为会被归并)。
最容易忽略的两件事
第一,IPv6 常常不跟着走。很多代理工具只接管 IPv4,而系统同时持有 IPv6 地址。结果是:网站优先走 IPv6,直接拿到你的真实地址,代理形同虚设。判断方法很简单——打开只显示 IPv6 的测试页,看它显示的地址是不是你代理出口的。
第二,ASN 类型比国家更有判别力。出口落在哪个国家可以伪装,但"这个 ASN 是云厂商机房"很难伪装成"住宅宽带"。大量账号共用同一个机房 ASN,本身就是可疑特征。
自测
curl -s https://www.cloudflare.com/cdn-cgi/trace
返回里的 ip= 是出口地址,loc= 是国家,warp= 表示是否走了 WARP。对比开/关代理两次的结果,差异就是你的代理实际接管了什么。IPv6 另用 test-ipv6.com 单测。
缓解与局限
缓解:确保 IPv4 与 IPv6 都被接管;优先选择与你"声称位置"自洽的出口类型。局限:IP 是共享资源,住宅代理的出口可能被上百人共用——你继承了别人的历史,也把你的历史留给了下一个人。
第二层:DNS 解析
DNS 泄露的本质是:你访问了什么域名,被谁知道了。即使网页流量全程走代理,域名解析仍可能由本地网络、你的运营商、或一个你没意识到的第三方完成。
三条可能路径
- 系统解析器 → 运营商递归。最经典的一种:网页走代理,DNS 却问到了本地运营商,于是"你想访问哪些站"完全暴露。
- 系统解析器 → 公共 DoH。查询被加密了,但 DoH 服务商看到的是你的真实 IP 和全部查询记录。换了信任对象,不是消除了暴露。
- 隧道内解析。由代理端或出口侧解析。这才是"解析地与出口地一致"的形态。
EDNS Client Subnet:一个隐藏的子网泄露
为了让 CDN 就近返回,很多解析器会把你的子网前缀(而不是完整 IP)附加在查询里传给权威服务器。这既是隐私问题,也是一致性问题的来源:你的出口在洛杉矶,但 ECS 带着另一个国家的子网,CDN 会返回离那个国家近的节点,于是延迟、证书、甚至站点行为都可能对不上。
自测
dig +short TXT o-o.myaddr.l.google.com @ns1.google.com
这会返回解析请求最终由哪个 IP 发出。如果它不是你代理出口的地址,就是泄露。浏览器侧用 browserleaks.com/dns 或 dnsleaktest.com,看"解析器所在地"是否与出口一致。
缓解与局限
缓解:让解析在隧道内完成,或统一使用与出口同地区的 DoH/DoT 解析器;确认 ECS 行为符合你的预期。局限:DoH 只加密"查询内容",不隐藏"谁在问";而解析器本身就是一个新的信任点。
第三层:WebRTC 与 STUN
WebRTC 是为实时音视频设计的,为了打洞,它必须知道"我能用哪些地址联系到我"。于是浏览器会向 STUN 服务器询问我的公网地址是什么,并把结果放进 ICE 候选列表。问题在于:这些 UDP 包默认不走 HTTP 代理。
会暴露什么
- srflx(服务器反射)候选:STUN 服务器看到的你的公网 IP —— 也就是真实出口。这是最常被引用的"WebRTC 泄露"。
- host(本地)候选:历史上会直接给出局域网地址(如
192.168.x.x)。现代浏览器用 mDNS 混淆把它替换成随机域名,但这是缓解,不是消除。 - NAT 类型与候选数量:旁路信息,可用于扩充指纹。
控制手段
Chromium 系有一个明确的策略项 WebRtcIPHandlingPolicy,常用取值包括:默认、仅暴露公网接口、禁止非代理 UDP。最后一项会把 WebRTC 流量也纳入代理(或被阻断)——这也是企业环境常配的策略。
代价要算清楚:禁止非代理 UDP 会让音视频通话质量下降甚至不可用。所以正确顺序是:先确认自己是否真的在用 WebRTC,再决定是否收紧,而不是无脑关掉。
自测
打开 browserleaks.com/webrtc,看 Public IP 与你的代理出口是否一致;再看 Local IP 是 mDNS 随机域名还是真实内网地址。
第四层:浏览器与设备指纹
这一层不需要任何权限,几十行 JS 就能读完。它的可怕之处不在单点,而在组合后的熵:往往只需要几项,全世界就只剩你一个。
| 信号 | 读取方式 | 熵值 | 能否改 |
|---|---|---|---|
| Canvas 渲染结果 | 绘制文字/图形后取像素哈希 | 很高 | 会随 GPU/驱动/字体变化,但难精确控制 |
| WebGL 渲染器 | UNMASKED_RENDERER_WEBGL | 很高 | 直接暴露显卡型号 |
| AudioContext | 生成音频后取浮点指纹 | 高 | 浮点实现差异,几乎无法伪装 |
| 字体列表 | measureText 逐字测量 | 高 | 与系统安装的字体强相关 |
| 屏幕与 DPR | screen / devicePixelRatio | 中 | 可改,但改了容易与分辨率不匹配 |
| 硬件并发数 | navigator.hardwareConcurrency | 中 | 暴露 CPU 核心数 |
| 设备内存 | navigator.deviceMemory | 低 | 粗粒度 |
| 时区 | Intl.DateTimeFormat().resolvedOptions().timeZone | 中 | 最容易被忽略、也最该一致 |
| 语言 | navigator.language(s) | 中 | 可与地区分离 |
| UA / Client Hints | navigator.userAgentData | 中 | UA-CH 替代了长 UA,但仍是特征 |
| 媒体设备数量 | enumerateDevices() | 低 | 需权限才给出标签 |
自测
- EFF Cover Your Tracks —— 给出"你的浏览器有多少位可识别信息"。
- AmIUnique —— 在一批样本里看你的唯一性排名。
- BrowserLeaks —— 逐项查看原始值,最适合定位矛盾项。
缓解与局限
有效方向有两个:把每个站点隔离在不同的容器里(跨站无法把同一指纹串起来),或降低独特性(取消个性化字体、非主流分辨率与插件组合)。
无效甚至有害的方向:随机化每一项。随机的组合落在真实设备参数空间的边缘,比一个普通的真实配置更醒目。这一点与直觉相反,但几乎是所有指纹研究的共同结论。
第五层:TLS 与协议栈指纹
这一层最容易被忽略,因为它不经过 JS、无法被页面脚本读取,而是在握手阶段被动采集。
- TLS 指纹(JA3/JA4):客户端问候里的版本、密码套件顺序、扩展列表与顺序、椭圆曲线等,组合成一个哈希。不同客户端(浏览器、curl、Python、某个代理软件)差异明显。
- HTTP/2 设置:初始窗口大小、最大并发流、帧顺序。
- TCP/IP 协议栈:TTL、窗口缩放、MSS 等,常被用于粗判操作系统。
实际意义:如果你用浏览器正常访问,TLS 指纹是浏览器的;但如果你的流量经过某个本地代理客户端,指纹可能变成那个客户端的——于是一个"声称是 Chrome 的请求"带着一个"Python 客户端"的指纹,这就是矛盾。
第六层:行为与内容痕迹
前五层都能被工具改变,这一层不行。
- 时段:你的活跃时间会长期落在某个时区的工作时段里。这是最难伪装的一项,因为它需要你改变作息。
- 输入节奏:键击间隔、鼠标轨迹、页面停留时间。有研究显示其可区分度相当高。
- 写作风格:用词偏好、标点习惯、中英混排方式、常用句式。跨账号跨平台都能比对。
- 命名与身份习惯:同一个小写 ID、同一段个人简介、同一个头像哈希,会直接把多个账号串起来。
- 内容里的实体:代码里的私有仓库路径、截图里的窗口标题、文档作者字段、图片 EXIF。
这一层的"抹除"不是技术问题,而是纪律问题:不同身份之间不要共用任何一处习惯——包括幽默感。
矛盾矩阵:位置、时区、语言、指纹
单看每一项都不致命,但两组信息对不上时,可识别性会急剧上升。这是本站反复强调"一致性"的原因,也是工具能力的边界所在。
| 矛盾组合 | 为什么显眼 | 修复方向 |
|---|---|---|
| 出口在美国,时区是 Asia/Shanghai | 真实用户不会带着出发前的时区跨境办公 | 时区跟随实际所在地 |
| 出口在机房 ASN,却声称是家庭网络环境 | ASN 类型难以伪装 | 换出口类型,或不让它成为矛盾点 |
| IPv4 走代理,IPv6 直连 | 两个地址同时属于你,且地理位置不同 | 双栈一起接管 |
| WebRTC 公网候选 ≠ 出口 IP | 同一次会话里出现了两个"你的地址" | 收敛 WebRTC 策略 |
| DNS 解析地在 A 国,出口在 B 国 | CDN 与证书行为都会异常 | 解析地与出口地一致 |
| UA 说 Windows,GPU 却是 Apple 型号 | 设备参数空间里不存在这种组合 | 整体一致,不做逐项伪装 |
| 语言是中文,区域格式却是美式日期 | 两项设置分属两个世界 | 语言保持母语,区域跟随地区 |
"抹除"能到哪一级
把预期校准到现实:下列五级的防护强度差别很大,而"抹除"这个词只对前三级成立。
| 级别 | 做法 | 挡住什么 | 挡不住什么 |
|---|---|---|---|
| L1 清理 | 退出登录、清 Cookie 与缓存、无痕窗口 | 本地状态被关联 | IP、DNS、WebRTC、指纹,全部照旧 |
| L2 换出口 | 代理或 VPN | IP 与 ASN(若配置正确) | DNS/WebRTC 泄露、指纹、TLS、行为 |
| L3 容器化 | 每站点独立容器/独立配置文件 | 跨站把同一指纹串起来 | 同一容器内的关联、网络层泄露 |
| L4 抗指纹 | 专门的抗指纹浏览器,统一或隔离指纹面 | 大部分 JS 层熵值 | 协议栈指纹、行为特征、账号与现实身份的绑定 |
| L5 匿名网络 | Tor 一类设计目标即匿名的网络 | 出口与来源的关联 | 仍可能被行为特征与账号行为去匿名化;且代价是可用性 |
自测清单
按顺序做完,比读完本文更有用。每一项都给了判断标准,而不是"打开看看"。
- IPv4 出口:
curl -s https://www.cloudflare.com/cdn-cgi/trace的ip=是否与你预期的出口一致 - IPv6 出口:同一命令强制 IPv6(
curl -6),是否仍指向预期出口 - ASN 类型:查出口 IP 的 ASN,确认它是住宅/移动而非云机房
- DNS 解析源:
dig +short TXT o-o.myaddr.l.google.com @ns1.google.com返回的地址是否等于出口 - DNS 解析地:browserleaks 的 DNS 页里,"解析器所在地"与出口国家是否一致
- WebRTC 公网候选:Public IP 是否等于出口 IP
- WebRTC 本地候选:Local IP 是 mDNS 随机域名还是真实内网地址
- 时区:
Intl.DateTimeFormat().resolvedOptions().timeZone与出口国家是否说得通 - 语言与区域:语言可以是母语,但区域格式不应与出口国家冲突
- GPU 与平台:WebGL 的 renderer 与 UA 声明的平台是否在同一参数空间内
- 指纹唯一性:Cover Your Tracks 的可识别位数,以及 AmIUnique 的样本排名
- TLS 指纹:用浏览器直接访问与经本地客户端访问,握手特征是否发生突变
六个常见误判
- "无痕模式 = 隐身":它清的是本地状态。服务端看到的 IP、时区、字体、GPU 一个都没变。
- "开了 VPN 就没泄露":DNS 与 WebRTC 都可能绕过隧道;IPv6 更是经常被漏掉。
- "改 UA 就更隐蔽":UA 只是众多信号之一,改了它而其它参数不变,反而制造了新的矛盾。
- "随机化指纹更安全":随机组合常落在真实设备空间的边缘,独特性升高而不是降低。
- "DoH 就等于隐私":查询加密了,但 DoH 服务商知道谁在问、问了什么。
- "换个新设备就干净了":新设备有全新的指纹,但行为习惯、账号、支付方式仍然指向同一个人。
边界与伦理
三点必须写在明处:
- 本页讲的是自我防护与自测方法,目的是让你知道自己的信息从哪些地方流出去、怎么减少。它不提供伪造身份、规避法律责任或实施欺诈的方法。
- 没有"彻底抹除"。你能做的是降低可关联性、减少不必要的暴露、让各层不自相矛盾。任何承诺"完全隐身"的说法都值得怀疑。
- 合规风险要自己承担。在某些场景下,刻意伪造网络位置或设备标识本身就违反平台条款或当地规定。技术上可行不等于合规上无风险。
参考与出处
| 内容 | 类型 | 出处 |
|---|---|---|
| 浏览器可识别信息与"位数"评估 | 权威测试工具 | EFF Cover Your Tracks |
| 逐项原始值与指纹/WebRTC/DNS 测试 | 测试工具 | BrowserLeaks |
| 指纹样本唯一性排名 | 研究数据集 | AmIUnique |
| IPv6 连通性与双栈测试 | 测试工具 | test-ipv6.com |
| DNS 解析器来源检测 | 测试工具 | DNSLeakTest |
| WebRTC 候选地址与策略 | 浏览器行为 | Chromium 的 WebRtcIPHandlingPolicy 策略项,取值含义见浏览器策略文档 |
| EDNS Client Subnet | 协议机制 | RFC 7871(ECS 的定义) |
| mDNS 隐藏本地候选 | 浏览器行为 | 现代 Chromium 对 host 候选使用 mDNS 混淆 |
上表里标注为"测试工具"的链接,请打开后自行比对;标注为协议或浏览器行为的,属于规范层面的机制,可以按名称检索原文。
开无痕模式能隐藏身份吗?
不能。无痕模式只清理本地 Cookie、缓存与历史。出口 IP、时区、语言、字体、GPU、Canvas 结果全部不变,服务端看到你和普通模式几乎一样,区别只是没有本地状态可关联。
用了 VPN 就不会有 DNS 泄露了吗?
不一定。查询可能绕过隧道走系统解析器,或在隧道内被转发到出口地的解析器。判断标准是解析请求最终由谁发出、ECS 是否携带了与你出口不符的子网——而不是你有没有开 VPN。用 dig +short TXT o-o.myaddr.l.google.com @ns1.google.com 直接看。
把指纹改成随机值是不是更安全?
往往更糟。随机化会产生现实中不存在的参数组合,比一个普通的真实配置更独特。方向是「变得不显眼」,不是「变得奇怪」。