你设置了代理,打开 IP 查询页面,显示的是代理的 IP。大功告成了吗?不一定。页面仍然可以通过 WebRTC 找到你的真实 IP,这是一项按设计会忽略浏览器代理设置的浏览器功能。如果你使用住宅代理以本地访客的身份查看网站,WebRTC 泄漏可能在没有任何明显迹象的情况下让这一切失效。
本指南解释泄漏的原理、如何在两分钟内测试,以及如何在 Chrome、Firefox 和自动化浏览器中堵住它。
泄漏是如何发生的
WebRTC 让浏览器之间可以直接通话和发送数据。为此,每个浏览器会收集“ICE 候选”:可能被访问到的地址。其中一步是通过 UDP 向 STUN 服务器询问:“你看到我来自哪个公网地址?”答案会进入一个候选项,页面的 JavaScript 可以读取它。
问题在于这个询问所走的路径。典型的 HTTP 代理只传输你的网页请求,不传输 UDP。所以 STUN 请求从你自己的网络连接发出,得到的答案就是你的真实公网 IP。RFC 8828 是 IETF 关于 WebRTC 地址处理的标准,它明确指出:如果允许直接访问互联网,STUN 检查可以绕过代理并暴露客户端的公网 IP。出于通话质量的考虑,它还建议默认不要让 WebRTC 流量经过代理。
有两个细节值得注意:
- **本地地址现在大多已被隐藏。**对于大多数页面,Chrome 和 Firefox 会用随机的
.local名称替换你的私有网络地址。在 Firefox 中,这是media.peerconnection.ice.obfuscate_host_addresses设置,默认开启。真正的风险是你的公网 IP。 - **页面不需要任何权限。**收集候选项不需要摄像头或麦克风权限,所以不会弹出提示。
两分钟完成测试
你不需要第三方测试网站。开启代理后,打开你关心的页面或任意页面,打开开发者控制台(F12),然后粘贴以下代码:
const pc = new RTCPeerConnection({ iceServers: [{ urls: "stun:stun.l.google.com:19302" }] });
pc.createDataChannel("t");
pc.onicecandidate = (e) => e.candidate && console.log(e.candidate.candidate);
pc.createOffer().then((o) => pc.setLocalDescription(o));
查看包含 typ srflx 的行。该行中的地址就是 STUN 服务器看到的公网 IP。
- 如果它与你的家庭或办公室 IP 一致,说明 WebRTC 正在泄漏。
- 如果它与代理的 IP 一致,或者根本没有
srflx行,说明没有问题。 - 包含
typ host和.local名称的行是你被隐藏的本地地址,出现它们是正常的。
然后在同一个浏览器中,与 IP Info 这类 IP 查询结果对比。它应该显示代理的 IP 和位置。如果查询显示的是代理,而 srflx 行显示的是你,说明代理本身工作正常,是 WebRTC 绕过了它。
在 Chrome 中修复
**最简单:使用能管理它的扩展。**连接期间,Shifter 浏览器扩展默认开启 WebRTC 泄漏防护。在底层,Chrome 扩展通过 webRTCIPHandlingPolicy 隐私设置来控制它。如果另一个扩展已经在控制 WebRTC,两者中只有一个能生效,Shifter 扩展会在它的防护未生效时告诉你。请移除或停用另一个扩展。
**受管理的电脑:**Chrome 有一项企业策略 WebRtcIPHandling,有四个取值:
| 取值 | WebRTC 使用的网络 |
|---|---|
default | 所有可用的网络接口 |
default_public_and_private_interfaces | 面向公网的接口,允许私有地址 |
default_public_interface_only | 仅面向公网的接口,不含私有地址 |
disable_non_proxied_udp | 经过代理的 TCP;只有代理支持时才使用 UDP |
只有 disable_non_proxied_udp 能在使用代理时阻止公网 IP 泄漏。两个“公网接口”取值仍然会通过你自己的网络连接询问 STUN 服务器。
在 Firefox 中修复
Shifter 扩展在 Firefox 中同样会处理。如果要手动设置,请打开 about:config 并设置:
- 将
media.peerconnection.ice.proxy_only_if_behind_proxy设为true:只有在配置了代理时,WebRTC 才使用代理。这是针对性的修复。 - 将
media.peerconnection.ice.default_address_only设为true:只使用默认路由。这会隐藏额外的本地地址,但仅靠它并不能阻止公网 IP 泄漏。 - 将
media.peerconnection.enabled设为false:完全关闭 WebRTC。这是最粗暴的选项,会让该浏览器中的通话无法使用。
然后再次运行控制台测试:srflx 行应该消失,或者显示代理的 IP。
在自动化浏览器中修复
Playwright、Puppeteer 和 Selenium 会启动真实的浏览器,所以泄漏方式相同。对于 Chromium,请使用以下参数启动:
--force-webrtc-ip-handling-policy=disable_non_proxied_udp
对于 Firefox,请在你的框架所启动的配置文件中设置相同的 about:config 首选项。然后在脚本中运行上面的控制台测试,并把检查 srflx 结果作为设置检查的一部分。我们的指南在 Selenium 和 Playwright 中配置住宅代理展示了这些选项应该放在哪里。
WebRTC 不是唯一的泄漏
趁此机会堵上相关的漏洞:
- **DNS。**域名解析可能绕过代理,从你自己的网络解析。我们的指南防止 DNS 泄漏介绍了
socks5h以及如何检查。 - **IPv6。**如果你的代理路径只支持 IPv4,同时具有 IPv6 的浏览器可能会对部分请求使用 IPv6。
- **时区和语言。**它们不会暴露你的 IP,但可能与代理所在的位置相矛盾。
总结
WebRTC 泄漏的原因是浏览器通过 UDP 向 STUN 服务器询问你的地址,而大多数代理只传输网页流量。用控制台代码测试:如果 srflx 地址是你的,页面也能看到它。在 Shifter 扩展中开启泄漏防护,或者在 Chrome 中设置 disable_non_proxied_udp、在 Firefox 中设置 proxy_only_if_behind_proxy,然后再次测试。