WebRTC疑似可以获取你的真实IP地址 | 在线检测工具 附源码

杂谈

之前看到有热心网友分享了一个溯源小技巧,很多热心网友使用代理时,可能都会忽略的问题,那就是没有禁止UDP协议中的STUN,这种情况极大程度上会造成你的真实IP地址泄露

相关阅读

效果演示

你只需要访问上面的页面,就可以获取到自己IP的使用情况了,包括

  • 服务器端通过XFF头或者CDN上获取的你的IP地址
  • 通过WebRTC获取的你的IP地址
图片[1]-WebRTC疑似可以获取你的真实IP地址 | 在线检测工具 附源码-FancyPig's blog

至于第一行为什么会和第三行出现不一致的情况,那就是取决于你使用代理时的模式了

比方说规则模式出现这样的情况是很正常的,如果是全局模式,通常情况下这两者会是一致的

在上面我们分享的文章中,里面有讲解到一些防止WebRTC获取到源IP地址的方式,譬如在IOS的🚀软件中,通常,你需要设置-UDP-禁用STUN,默认情况下,这个选项是不被禁用的,因此,你在手机上浏览一些内容时,恰巧服务端又是使用WebRTC获取的IP地址,那么,你很有可能会被记录到真实的IP地址,导致最终被溯源

图片[2]-WebRTC疑似可以获取你的真实IP地址 | 在线检测工具 附源码-FancyPig's blog

让ChatGPT写一个WebRTC的获取代码

  • 功能实现
  • 页面优化
图片[3]-WebRTC疑似可以获取你的真实IP地址 | 在线检测工具 附源码-FancyPig's blog

页面设计优化

图片[4]-WebRTC疑似可以获取你的真实IP地址 | 在线检测工具 附源码-FancyPig's blog

代码部署

当然,你如果也想部署一个类似于这样的蜜罐,也可以使用下面的代码

  • get_real_ip.php 用于获取XFF、CDN的IP
  • index.html 前端界面

get_real_ip.php

<?php
function getUserIP() {
    $ip = '';
    if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
        $ip = $_SERVER['HTTP_CLIENT_IP'];
    } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
        $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
    } else {
        $ip = $_SERVER['REMOTE_ADDR'];
    }
    return $ip;
}

header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');

$ip = getUserIP();
echo json_encode(['ip' => $ip]);
?>

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Get IP Addresses</title>
    <link rel="stylesheet" href="https://unpkg.com/element-ui@2.15.6/lib/theme-chalk/index.css">
    <script src="https://unpkg.com/vue@2.6.14"></script>
    <script src="https://unpkg.com/element-ui@2.15.6/lib/index.js"></script>
</head>
<body>
    <div id="app">
        <el-container>
            <el-header>
                <h1>Your IP Addresses:</h1>
            </el-header>
            <el-main>
                <el-table :data="ipAddresses" style="width: 100%" border>
                    <el-table-column prop="type" label="Type" width="180"></el-table-column>
                    <el-table-column prop="address" label="IP Address"></el-table-column>
                </el-table>
            </el-main>
        </el-container>
    </div>

    <script>
        new Vue({
            el: '#app',
            data() {
                return {
                    ipAddresses: [
                        { type: 'XFF or CDN IP Address', address: 'Loading...' },
                        { type: 'WebRTC Local IP Address', address: 'Loading...' },
                        { type: 'WebRTC IPv4 Address', address: 'Loading...' },
                        { type: 'WebRTC IPv6 Address', address: 'Loading...' }
                    ]
                };
            },
            mounted() {
                // Fetch XFF or CDN IP address
                const xhr = new XMLHttpRequest();
                xhr.open('GET', 'get_real_ip.php', true);
                xhr.onreadystatechange = () => {
                    if (xhr.readyState === 4 && xhr.status === 200) {
                        const jsonResponse = JSON.parse(xhr.responseText);
                        this.ipAddresses[0].address = jsonResponse.ip;
                    }
                };
                xhr.send();

                // WebRTC IPs
                const iceServers = [
                    { urls: 'stun:stun.l.google.com:19302' },
                    { urls: 'stun:stun1.l.google.com:19302' },
                    { urls: 'stun:stun2.l.google.com:19302' },
                    { urls: 'stun:stun3.l.google.com:19302' },
                    { urls: 'stun:stun4.l.google.com:19302' },
                ];
                // getUserIPs function
                function getUserIPs(callback) {
                    const myPeerConnection = new RTCPeerConnection({ iceServers });
                    myPeerConnection.createDataChannel("");
                    myPeerConnection.createOffer().then(offer => myPeerConnection.setLocalDescription(offer));
        
                    myPeerConnection.onicecandidate = function(event) {
                        if (event.candidate) {
                            const parts = event.candidate.candidate.split(' ');
                            const ip = parts[4];
                            callback(ip);
                        }
                    };
                }

                getUserIPs((ip) => {
                    // ... (same as before)
                                const ipv4Regex = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
            const ipv6Regex = /^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}(([0-9a-fA-F]{1,4}:){1,4}|((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/;
                    if (ipv4Regex.test(ip)) {
                        this.ipAddresses[2].address = ip;
                    } else if (ipv6Regex.test(ip)) {
                        this.ipAddresses[3].address = ip;
                    } else {
                        this.ipAddresses[1].address = ip;
                    }
                });
            }
        });
    </script>
</body>
</html>

© 版权声明
THE END
喜欢就支持一下吧
点赞16赞赏 分享
评论 共3条

请登录后发表评论