Appearance
WebRTC 会泄露真实 IP 吗?怎么检测和防护(前端 JS 实现)
先给结论:会,而且你开着代理也挡不住。 浏览器里的 WebRTC 为了建立 P2P 连接,会主动向 STUN 服务器暴露你的真实公网 IP,这个「暴露」绕过了系统代理,VPN 开着也一样漏。网上那些「WebRTC 泄漏测试」工具站,测的就是这个。对做风控、做内容平台的人来说,这事反过来是个机会:用户挂代理伪装归属地,WebRTC 却可能把真实位置抖出来。
一、WebRTC 为什么会「漏」
WebRTC 是浏览器里的音视频实时通信能力,视频通话、在线会议、网页连麦都是它。它有一个叫 ICE 的机制:为了让两个人在不同的网络环境里也能直连,浏览器会主动收集自己所有的网络地址(本地地址、公网地址、通过 STUN 服务器探测到的映射地址),这堆地址叫 ICE candidate,拿来和对方交换。
问题就出在「主动收集公网地址」这一步。浏览器会尝试用 UDP 直连 STUN 服务器(比如 Google 的 stun.l.google.com:19302),STUN 服务器一看:「哟,你的公网 IP 是这个」,就记下来了。这个行为发生在浏览器底层,用的不是 HTTP 代理链路,所以系统代理、浏览器代理、甚至大多数 VPN 客户端都管不着它——你的真实公网 IP 就这么被浏览器自己说出来了。
Chrome 后来的版本默认用 mDNS 混淆(candidate 里显示成 xxx.local),但这只是把「局域网 IP」藏了,公网 IP 照样能从 STUN 服务器拿到,只是获取方式稍微绕一点。Firefox 默认则可以直接读出公网地址。
二、检测:一个页面脚本搞定
写一个页面,用原生 RTCPeerConnection 强行触发 ICE 收集,把 candidate 里的 IP 地址捞出来过滤出公网 IPv4。下面是完整可运行的检测脚本:
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>WebRTC 泄露检测</title>
</head>
<body>
<h3>WebRTC 真实 IP 检测</h3>
<p>点击按钮,看浏览器是否泄露公网 IP:</p>
<button onclick="detect()">开始检测</button>
<pre id="result">等待检测…</pre>
<script>
// 用原生 WebRTC 收集 ICE candidate,提取其中的 IP 地址
async function getWebRTCIPs() {
return new Promise((resolve) => {
const ips = [];
const pc = new RTCPeerConnection({
iceServers: [
{ urls: 'stun:stun.l.google.com:19302' },
{ urls: 'stun:stun1.l.google.com:19302' }
]
});
// 创建数据通道,强制触发 ICE 流程(纯音频/视频对等连接也一样)
pc.createDataChannel('probe');
pc.onicecandidate = (e) => {
if (!e.candidate) {
pc.close();
resolve(ips);
return;
}
const c = e.candidate.candidate;
// candidate 形如:candidate:... 1 udp 2113937151 1.2.3.4 54321 typ srflx
const m = c.match(/(\d{1,3}(?:\.\d{1,3}){3})/);
if (m && !ips.includes(m[1])) {
ips.push(m[1]);
}
};
// 30 秒兜底,防止某些浏览器不触发 onicecandidate
setTimeout(() => { pc.close(); resolve(ips); }, 30000);
});
}
async function detect() {
const out = document.getElementById('result');
out.textContent = '正在检测…';
const ips = await getWebRTCIPs();
out.textContent = '检测到的 IP 列表:\n' + (ips.length ? ips.join('\n') : '(没测到公网 IP,可能被 mDNS 混淆或浏览器限制)');
}
</script>
</body>
</html>存成 html 直接双击打开(需要挂代理/VPN 的情况下测,效果最明显:列表里那个不在你代理出口 IP 段里的,就是被 WebRTC 漏出来的真实 IP)。检测到 IP 后,把每个 IP 贴进 https://ip9.com.cn/get?ip=xxx 查归属地,能看到它们各自的省市和运营商。
三、风控视角:WebRTC「帮」你抓伪装用户
如果只当个测试工具,那这事没多大价值。真正有用的是反着用:用户口口声声在国内,IP 归属地也显示在国内,但他的 WebRTC 漏出的 IP 归属地在国外——对不上号。
具体做法三步:
- 页面加载时用上面脚本收集 WebRTC IP 列表;
- 同一个接口请求里带上用户正常访问的出口 IP(服务端拿到的源 IP);
- 后端把 WebRTC IP 和出口 IP 分别查归属地,比对国家和省份。
这里有个细节:WebRTC 在浏览器里是「可能泄露」,不是「必然泄露」,而且伪装用户也可能直接禁掉 WebRTC。所以正确的用法是当辅助信号,配合其他维度用。单独一个 WebRTC 信号不能定罪,但它能大幅提升对可疑账号的怀疑权重。放在前端做的是「收集」,放在后端做的是「比对」——把收集到的 IP 列表 POST 给接口,后端统一查归属地。
四、JS 后端比对示例(Node.js)
前端收集到 IP 后,交给 Node 后端比对(生产环境建议对收集接口加频控,防止被刷):
javascript
// compare.js —— 比对「声称的出口 IP」与「WebRTC 泄露 IP」的归属地
// 用法:node compare.js <出口IP> <WebRTC IP1> [WebRTC IP2...]
const https = require('https');
function queryGeo(ip) {
// ip9.com.cn 免费版:get?ip= 查指定 IP,返回国家/省市/运营商
return new Promise((resolve) => {
https.get(`https://ip9.com.cn/get?ip=${encodeURIComponent(ip)}`, (res) => {
let body = '';
res.on('data', (c) => (body += c));
res.on('end', () => {
try {
const d = JSON.parse(body);
resolve(d.data || null);
} catch (e) {
resolve(null);
}
});
}).on('error', () => resolve(null));
});
}
async function main() {
const exitIP = process.argv[2];
const webRTCIPs = process.argv.slice(3);
if (!exitIP || webRTCIPs.length === 0) {
console.log('用法: node compare.js <出口IP> <WebRTC IP1> [IP2...]');
return;
}
const exitGeo = await queryGeo(exitIP);
console.log(`出口 IP ${exitIP} → ${exitGeo ? exitGeo.country + exitGeo.prov + exitGeo.city : '查询失败'}`);
for (const ip of webRTCIPs) {
if (ip === exitIP) continue; // 与出口一致,正常
const geo = await queryGeo(ip);
if (!geo) continue;
const flag = (geo.country !== exitGeo.country) ? '⚠️ 跨国不一致' : '正常';
console.log(`WebRTC ${ip} → ${geo.country + geo.prov + geo.city} ${flag}`);
}
}
main();node compare.js 61.140.0.1 202.4.12.3,输出里出现「⚠️ 跨国不一致」,就是典型的代理伪装线索:出口 IP 是中国宽带,WebRTC 漏出的却是海外 IP。免费版 60 次/分钟/IP 的额度,做逐条比对完全够;如果要做全量实时比对且量很大,再看 VIP。
五、落地注意事项
- 误报率要认:公司网络、学校网络下,多个用户可能共享同一出口 IP,WebRTC 和出口 IP 对不上不一定是伪装。信号要打分制,别用一刀切。
- mDNS 影响:Chrome 下 candidate 可能先给
.local,在上面脚本里就会被过滤掉,测不到。这时换 Firefox 或让用户允许站点使用本地网络权限,能提高捕获率。 - 合规:收集用户 WebRTC 地址涉及隐私,页面要提示用途;只把「比对结果」落库而不是存原始 IP,审计压力小很多。
- 用户侧怎么防:真要在意泄露,Firefox 里
about:config关掉media.peerconnection.enabled,Chrome 装 WebRTC 控制类插件,或全局走支持 UDP 代理的客户端(Clash 的 TUN 模式能覆盖 WebRTC 流量)。
总结
WebRTC 泄露不是洪水猛兽,对工具站是「防」,对风控是「用」。检测脚本十行就能跑起来,配合 IP 归属地接口做出口 IP 与真实 IP 的比对,识别代理伪装账号的成本很低。接口就是 https://ip9.com.cn/get?ip=xxx,免费版单 IP 查询、60 次/分钟、无需注册,字段含国家、省市、运营商、经纬度,够用。想了解免费版和 VIP 版(区县、ip_type、ASN)的完整功能差异,去官网 https://www.ip9.com.cn 看功能清单。