WebRTC 泄漏:VPN 开着,IP 为什么还是露了
WebRTC 为了打通点对点连接,会主动向 STUN 服务器问自己的公网地址,这一步经常绕过 VPN。这篇讲它的原理、为什么在中国测它要用国内 STUN、以及关掉它要付出什么代价。
5 分钟阅读 · 发布于 2026年9月10日
挂着梯子打开一个 IP 查询站,页面显示的是日本或美国的地址,你就放心了。可同一个页面的 JavaScript 可能已经悄悄拿到了你在中国的真实公网 IP,方法不是什么漏洞,而是浏览器一个正经的功能:WebRTC。
WebRTC 本来是干什么的
WebRTC 是浏览器内置的实时通信能力,网页视频会议、网页电话、部分网盘的点对点传输都靠它。它的核心对象叫 RTCPeerConnection。两个浏览器要直接连上,得先知道对方"从公网看是什么地址",这个找地址的过程叫 ICE(Interactive Connectivity Establishment)。
ICE 会收集若干个"候选地址"(candidate),大致分三类:
- host 候选:本机网卡上的地址,比如
192.168.1.23。 - srflx(server reflexive)候选:向一台 STUN 服务器发个 UDP 包,服务器把它看到的来源地址回给你——这就是你的公网出口 IP。
- relay 候选:走 TURN 中继服务器,通常需要账号,泄漏问题里不重要。
关键在于,这些候选会通过 onicecandidate 事件和 SDP 文本原封不动地交给页面脚本。页面根本不需要真的建立通话,创建一个 RTCPeerConnection,加一个 data channel,调 createOffer,几百毫秒后候选列表就躺在 JS 变量里了。不弹权限框,不提示用户。
STUN 是什么
STUN 说白了就是个"照镜子"服务:你发一个 UDP 包过去,它回一句"我看到你从 1.2.3.4:51234 来的"。协议本身很小,全球有大量公开的 STUN 服务器,Google 的 stun.l.google.com:19302 最有名,Cloudflare、Twilio 也提供。
正是因为它简单、无状态、走 UDP,才成了泄漏的入口。
为什么 VPN 挡不住它
这取决于你的梯子怎么接管流量。
常见的翻墙客户端有几种工作方式。一种是系统代理模式:客户端在本机开一个 SOCKS/HTTP 代理端口,然后把系统设置指向它。浏览器的 HTTP 请求会老老实实走代理,但 WebRTC 发的是 UDP 原始包,它压根不看系统代理设置,直接从默认网卡出去。于是 STUN 看到的就是你家宽带的公网 IP。
另一种是分流规则:客户端只对某些域名或 IP 段走代理,其余直连。STUN 服务器的地址往往不在规则里,直连出去,同样泄漏。仅代理 TCP 的配置也一样,UDP 直接漏过。
还有"只代理浏览器"的模式(浏览器插件式代理、或只给 Chrome 设了代理),效果与系统代理类似。
真正能挡住的是 TUN/全局模式:客户端创建一个虚拟网卡,改掉系统路由表,所有流量不分协议都进隧道。这时 STUN 看到的是出口节点的 IP,与 HTTP 出口一致,测试结果就会显示"无泄漏"。
所以 WebRTC 测试看的不只是"漏没漏",它顺带告诉你工具到底接管了多少流量。
mDNS 混淆:局域网 IP 基本不再泄漏
几年前 WebRTC 还会把 host 候选里的内网地址直接暴露,网站能看到你在 192.168.x.x 还是 10.x.x.x,甚至能据此推断你在公司还是在家。现在 Chrome 和 Firefox 默认改成用 mDNS 名替换,你看到的候选会是 a1b2c3d4-….local 这种随机字符串而不是 IP。
这解决了内网地址的问题,但 srflx 候选(公网 IP)没有被混淆——它本来就是 ICE 打洞必需的信息。也就是说,2026 年的浏览器里,WebRTC 泄漏主要指的是公网 IP 泄漏。
为什么在中国要用国内 STUN 服务器测
这一点很多测试站做错了。
如果测试页面只请求 Google 的 STUN,而你在中国大陆直连——不管是因为没开代理,还是因为 UDP 被分流直连——那个包很可能被丢弃或超时,什么候选都收不到。页面于是显示"未检测到泄漏"。这不是没泄漏,是探针够不着。
反过来,走代理的那一侧能顺利到达 Google STUN,返回出口节点 IP,看上去一切正常。真正的直连出口从来没被测到。
browserscan 的做法是同时向一批 STUN 服务器发请求,既有 Google、Cloudflare、Twilio 这样的境外服务,也有小米、QQ、bilibili 等国内公司运营的 STUN。国内 STUN 在境内直连一定能到,如果你的 UDP 没进隧道,它就会回报你的真实宽带 IP。本站的 WebRTC 检测 采用同样的思路:多个服务器并发,把每一个返回的公网地址和 HTTP 层看到的 IP 逐一对比,任何一个不一致都算泄漏。
顺带一提,这也解释了为什么有人在境外测试站上"没泄漏",换个站就"泄漏了"。
怎么防
选项按代价从小到大排:
让梯子接管全部流量。 把客户端切到 TUN 或全局模式,并打开 kill switch(隧道断了就切断网络,而不是回退直连)。这是最根本的办法,浏览器功能一个都不用牺牲。
Firefox。 地址栏输入 about:config,搜索 media.peerconnection.enabled,改成 false。WebRTC 整个关闭。
Chrome / Edge。 没有内置开关。可以装 Google 官方的 WebRTC Network Limiter 扩展,选择"仅使用默认公网接口"或"禁用非代理 UDP";uBlock Origin 的设置里也有"阻止 WebRTC 泄漏本地 IP 地址",勾上即可。
Safari。 没有面向用户的开关,只能靠代理层解决。
关闭 WebRTC 的代价是实实在在的:网页版视频会议(Google Meet、腾讯会议网页版之类)会连不上或者只能走中继,网页电话、浏览器里的 P2P 文件传输、部分网页游戏也会受影响。如果你每天都要开会,"限制"比"禁用"更合适。
常见问题
测试显示我的公网 IP 和 HTTP IP 一样,是不是就安全了? 在 WebRTC 这一项上是安全的,说明 UDP 也走了隧道。但它不能代表 DNS 没有泄漏,两者是独立的问题,见 DNS 泄漏与端口。
候选里只有 .local 结尾的名字,没有 IP,什么意思?
说明浏览器做了 mDNS 混淆,而且没有收到任何 srflx 候选——要么 STUN 全部不可达,要么 WebRTC 被扩展限制了。这种情况下测试给不出结论,不等于安全。
手机上会泄漏吗? 移动端浏览器同样有 WebRTC。不过手机上的翻墙客户端多数以 VPN(TUN)模式运行,天然接管所有流量,泄漏反而比桌面少见。用 iOS 的"仅代理"型客户端时仍然可能出现。