- NO.
- 009
- DATE
- 更新于 2026-07-20
- READ
- ~9 min
- KIND
- 教程
- STATUS
- 原文
WebRTC 泄漏自查:你的真实 IP 有没有漏出去
WebRTC 会在你不知情时暴露真实 IP:它不走普通请求、DevTools 也看不到。这篇讲清机制,并给出检测页和一段可直接贴进控制台的自查脚本。
WebRTC 泄漏大概是最容易被低估的一类隐私暴露,因为它看起来根本不像一次网络请求。
你以为挂了代理或 VPN 之后,页面只能看到出口 IP。但只要页面用到 WebRTC,浏览器为了建立点对点连接,就会在后台收集一批"网络候选项",里面可能夹带你的局域网地址,甚至你真实的公网 IP。关键在于:这套协商不走普通请求,打开 DevTools 的 Network 面板也看不到,所以大多数人从没注意过它——哪怕你平时对隐私已经挺在意。
这篇不是要卖某个解决方案(现成的方案和插件已经很多了),而是想把这件事讲清楚,再给你一套能自己上手的自查方法,让你看见之前一直没留意的那块暴露面。
泄漏是怎么发生的
WebRTC 在协商连接时会收集 ICE candidates,大致分三类:
- host candidate:本机网络接口上的地址,通常就是你的局域网地址。
- srflx candidate:通过 STUN 服务器看到的"公网映射地址"。
- relay candidate:通过 TURN 服务器中转的地址,只有你显式配了 TURN 才会出现。
好消息是,现状比几年前收敛了不少。现代 Chromium 系浏览器(Chrome、Edge、Brave 等)默认会把 host candidate 里的本机地址替换成一串随机的 .local 主机名(mDNS 匿名化),Firefox、Safari 也各有自己的收敛策略。所以在默认状态下,单纯的局域网地址泄漏其实已经被压下去了。
但有两个坑还在:
一是权限会改变收集行为。一旦你给某个站点授予了摄像头或麦克风权限,浏览器可能就不再对它做 mDNS 匿名化,而是直接给出真实的局域网地址。不同浏览器、不同版本的处理并不完全一致,这也是"我这台机器没漏、你那台却漏了"的常见原因。
二是 srflx 仍然可能漏出真实公网 IP。srflx 本身不是漏洞——直连时它就等于你的公网 IP,没什么好隐瞒的。问题出在代理/VPN 配置不当的时候:如果你以为流量都走了代理,但 WebRTC 的 STUN 查询实际是一条 UDP,绕过了只接管 HTTP/TCP 的浏览器代理,那么 srflx 里出现的就会是你真实的公网 IP,而不是代理出口。这时候页面看到的"出口 IP"是代理的,WebRTC 拿到的却是你本人的——两者对不上,就是泄漏。
再强调一遍那个最容易被忽略的点:这些协商不是 fetch、不是 XHR,也不是文档或资源请求,所以 DevTools 的 Network 面板里根本看不到(想看得用 chrome://webrtc-internals)。看不见,大概正是它长期被低估的主要原因。
怎么自查
好在自查的门槛很低,不用装任何东西。两条路:用现成的检测页,或者贴一段脚本进控制台。
建议在你平时真实使用的那个浏览器、那套代理/VPN 配置下测,而不是开一个干净环境测——因为你要验的正是日常配置有没有在漏。
用检测页
最直接的是这两个:
browserleaks.com/webrtcipleak.net
打开 browserleaks.com/webrtc,重点看两组字段:
- Local IP Address(对应 host):如果显示的是一串
.local结尾的主机名,说明 mDNS 匿名化在生效,局域网地址被挡住了;如果直接显示192.168.x.x、10.x.x.x、172.16~31.x.x这类内网地址,说明本机地址正在泄漏(常见于你曾给该站授予过摄像头/麦克风权限)。 - Public IP Address(对应 srflx):把它和你以为的出口 IP 比一比。如果你挂着代理/VPN,这里却是你真实的公网 IP,那就是 WebRTC 绕过了隧道。
ipleak.net 的用法类似:它会单独列一块 WebRTC 探测到的 IP,和页面顶部那个"你的 IP"对照着看,不一致就说明有东西漏在了预期路径之外。别忘了 IPv4、IPv6 两栏都要看——IPv6 常常是被忽略的那一档。
如果这两项什么都没显示(不是 .local、也不是内网地址,就是空白):别急着当成"检测页坏了"。大概率是你的浏览器或某个扩展已经把 WebRTC 候选项收集整个拦掉了——这本身通常是一种防护在生效,只是检测页没法区分"没测到"和"测到了但是空"这两种情况。往下看控制台脚本那一节,能看得更清楚该往哪个方向查。
用一段控制台脚本
如果你想看得更原始一点,或者想验证检测页有没有骗你,可以把下面这段直接贴进浏览器控制台(F12 → Console)回车。它会新建一个 RTCPeerConnection,收集候选项并逐条打印,大约几秒内出结果:
const pc = new RTCPeerConnection({
iceServers: [{ urls: "stun:stun.l.google.com:19302" }],
});
const seen = new Set();
pc.addEventListener("icecandidate", (e) => {
if (!e.candidate) {
console.log("— 收集结束 —");
return;
}
// 现代浏览器直接给出结构化字段;个别老版本可能为 null,回退到原始字符串
const { type, address, protocol } = e.candidate;
const line = address ? `${type}\t${protocol}\t${address}` : e.candidate.candidate;
if (seen.has(line)) return;
seen.add(line);
console.log(line);
});
// 需要一个 STUN 服务器才能看到 srflx(公网映射)候选项,这里用一个公共地址做示例
pc.createDataChannel("probe");
pc.createOffer().then((offer) => pc.setLocalDescription(offer));
输出怎么读:
- 看到
host那行的地址是xxxxxxxx.local这种主机名:mDNS 在生效,局域网地址被匿名化了,这是当前的健康状态。 - 看到
host那行是192.168.*、10.*、172.16~31.*这类内网地址:本机地址正在泄漏。 - 看到
srflx那行的公网 IP 和你的代理/VPN 出口对不上(是你真实的公网 IP):说明 WebRTC 绕过了代理/VPN。 - 没看到
relay那行:正常。示例里没配 TURN 服务器,自查场景本来就不会出现 relay,别误当成异常。 - 只有
host、没有srflx:host 候选项是纯本地生成的,不需要联网;缺的是 srflx,说明到 STUN 服务器的 UDP 被挡住了(常见于网络/防火墙,或代理只接管了 TCP)。换个网络再试,别直接下"没泄漏"的结论。 - 连
host都没有,只打出一行「— 收集结束 —」:这和上一条不是一回事,反而更值得留意。host 候选项本地就能生成,不用等网络,正常情况下几乎是立刻打出来的;如果它都没出现,大概率不是网络问题,而是浏览器或某个扩展在更早的层面就把 ICE 收集整个拦掉了——常见于开着 WebRTC 防护的扩展(比如下面提到的 uBlock Origin 那个选项)、Brave 的 Shields,或者浏览器本身把 WebRTC 关了。想确认是不是这个原因:打开chrome://webrtc-internals(Firefox 是about:webrtc)看有没有相关记录,或者临时关掉可疑的扩展/Shields 再跑一次脚本——这时候如果冒出了候选项,说明防护本来就生效,你测到的其实是"好消息";换了干净环境(比如无痕窗口 + 禁用所有扩展)还是空的,才需要继续往下查是不是 WebRTC 被整个关掉了(比如 Firefox 的media.peerconnection.enabled被设成了false)。
脚本能跑出来的东西,和检测页应当一致——包括"两边都是空的"这种情况:如果检测页的字段是空白、脚本也只打出「— 收集结束 —」,大概率是同一个原因(见上一条),而不是两边各自坏了。两边结果对不上时,以你能亲手复现的那个为准。
结果怎么解读
同一份输出,对不同人的意义不一样。按你的实际情况对号入座:
- 直连用户(没挂代理/VPN):你主要关心 host 那档。看到
.local就安心,看到内网地址说明本机地址被暴露——通常是某个站点拿到过你的摄像头/麦克风权限。srflx 等于你的真实公网 IP 是意料之中的,但值得知道:页面不发一个普通请求,也能通过 WebRTC 拿到它。 - 代理用户(浏览器级 HTTP/SOCKS 代理):你最该盯的是 srflx 和代理出口对不对得上。浏览器级 HTTP 代理很多时候压根不接管 UDP,STUN 一条 UDP 就把你真实公网 IP 漏了出去,而页面显示的还是代理 IP——这种"表面一致、底下不一致"最坑。
- VPN 用户(系统级 VPN):系统级隧道通常会把 STUN 也带进去,srflx 一般等于 VPN 出口。但要留意几种情况:分离隧道(split tunnel)可能把 WebRTC 放行到隧道外;VPN 只接管了 IPv4、WebRTC 却通过 IPv6 拿到 srflx,直接暴露你真实的 IPv6;以及断线重连那一瞬间的短暂裸奔。所以除了核对 srflx,还要特别看一眼有没有冒出意料之外的 IPv6 地址。
很多人第一次跑完会有点意外——原来自己一直以为遮住的东西,其实半开着。看见,就是这篇的目的。
缓解:现成方案已经够多
确认自己在漏之后,不用自己造轮子。可选的成熟做法已经不少,按你的浏览器挑一个就行:
- uBlock Origin:扩展图标 → 面板右下角齿轮(打开仪表盘)→「设置」标签页 → 勾选"防止 WebRTC 泄露本地 IP 地址"(英文版是 Prevent WebRTC from leaking local IP addresses)→ 保存。勾上之后的效果,就是前面提到的"host 候选项直接不出现,脚本只打出「— 收集结束 —」"那种表现——如果你已经开着这个选项,测出"什么都没有"是预期结果,不是 bug。
- Brave:设置 → 隐私和安全 → 搜索 "WebRTC",能看到 WebRTC IP 处理策略,可选"仅默认公网接口"(收敛 host,但保留 srflx)或更严格的"禁用非代理 UDP"(没走代理的 UDP 请求,包括 STUN 查询,直接失败——效果同样是"测不到候选项")。
- Firefox:地址栏输入
about:config,搜media.peerconnection.enabled设为false,整个关掉 WebRTC(代价是依赖它的应用会用不了,比如浏览器内视频通话)。想保留功能又收敛地址,改这两项更够用:media.peerconnection.ice.default_address_only设true(只暴露默认路由地址,压掉多网卡场景下的额外暴露面),media.peerconnection.ice.no_host设true(干脆不生成 host 候选项)。 - Chromium 企业策略:通过组策略/托管配置下发 WebRTC IP handling 相关策略(字段名随版本演进,早期文档里叫
WebRTCIPHandlingPolicy,现在部分场景细化进了WebRtcLocalIpsAllowedUrls之类更细粒度的策略),面向的是批量管控的 IT 场景,个人用户一般用不上,了解一下就好。 - 部分 VPN 客户端:自带的"WebRTC 防护"开关,本质也是上面几种手段之一(有的是系统级拦住 STUN 出站,有的是往浏览器注入类似 uBlock 那条规则的逻辑)。确认打开之后,别只看那个开关本身,还是要用检测页/脚本复验一遍——开关存在不等于对你这个版本的浏览器一定生效。
真正重要的是两点:挑一个你信得过的现成方案,别贪多叠一堆(叠多了连你自己都分不清是哪一层在生效,出问题也难排查);以及改完之后一定用上面的检测页或脚本复验一遍,看到"host 消失、脚本秒收尾"这种结果就是生效的证据,别停在"我设了个选项"的心理安慰上。
关于 NodePurity
我自己维护着一个叫 NodePurity 的小工具——不是浏览器插件,是一个跑在本地的命令行审计脚本,用在注册长期账号之前:先测一遍打算用的这个代理/VPN 出口节点"纯不纯"。出口地理位置、ASN/运营商类型(住宅/移动 IP 优于机房 IP)、DNS 解析器出口、IPv6 是否旁路暴露、Google/YouTube 触发程度,都会测一遍。WebRTC/STUN 泄漏是权重最高的一项:真实公网 IP 一旦通过 STUN 泄漏出来,不管其它分数多高,直接判"弃"——一票否决,这条踩了代理就等于没挂。我没打算在里面再造第 N 个 WebRTC 防护方案,防护交给上面那些成熟选项就够了;NodePurity 收的是另一个思路——跑完输出一份逐项列出扣分理由的报告,而不是一句笼统的"已优化"。
之所以强调"报告",是因为报告比静默修复更重要。一个安全或隐私工具如果只告诉你"已优化",实际价值很低;它该说清楚自己做了什么、没做到什么、下一步的风险在哪里,把判断权还给你。
也正因如此,我会刻意避免"彻底防指纹""百分百匿名""绕过所有检测"这类说法。WebRTC 只是浏览器诸多暴露面里的一个入口,Canvas、字体、时区、语言、设备信息、扩展痕迹都可能参与识别,把 WebRTC 收拾干净,不等于环境就"干净"了。更诚实的表述是:减少 WebRTC 带来的地址暴露,并且让结果可被你亲手验证。
所以这篇真正想留给你的,不是某个工具,而是一个习惯——花两分钟自查一次,看看你以为遮住的东西,是不是真的遮住了。
评论
评论由 GitHub Discussions 提供。登录 GitHub 后即可评论。 前往对应 Discussion