Können Sie die lokale LAN-IP-Adresse eines Benutzers über JavaScript abrufen?

102

Ich weiß, die erste Reaktion auf diese Frage ist "nein" und "es kann nicht gemacht werden" und "du solltest es nicht brauchen, du machst etwas falsch". Ich versuche, die LAN-IP-Adresse des Benutzers abzurufen und auf der Webseite anzuzeigen. Warum? Denn genau darum geht es auf der Seite, an der ich arbeite, und es werden so viele Informationen wie möglich über Sie, den Besucher, angezeigt: http://www.whatsmyip.org/more-info-about-you/

Ich mache also eigentlich nichts mit der IP, außer sie dem Benutzer zu Informationszwecken zu zeigen. Früher habe ich dazu ein kleines Java-Applet verwendet. Es hat ziemlich gut funktioniert. Aber heutzutage bringt Sie der Browser dazu, so oft zuzustimmen und zu vertrauen, dass Sie selbst das kleinste Java-Applet ausführen, dass ich lieber gar kein Applet ausführen möchte.

Also habe ich diese Funktion für eine Weile einfach losgeworden, aber ich würde sie gerne zurückhaben, wenn möglich. Es war etwas, das ich als Computerberater von Zeit zu Zeit tatsächlich benutzte. Auf dieser Website können Sie schneller feststellen, in welchem ​​IP-Bereich ein Netzwerk ausgeführt wird, als in den Systemeinstellungen, im Netzwerk und in der jeweils aktiven Schnittstelle.

Ich frage mich also und hoffe, ob es eine Möglichkeit gibt, dies allein in Javascript zu tun. Möglicherweise können Sie auf ein neues Objekt zugreifen, ähnlich wie Javascript den Browser fragen kann, wo sich der geografische Standort auf der Erde befindet. Vielleicht gibt es etwas Ähnliches für Client-Netzwerkinformationen? Wenn nicht, gibt es vielleicht einen ganz anderen Weg, dies zu tun? Ich kann mir nur ein Java-Applet oder ein Flash-Objekt vorstellen. Ich würde beides lieber nicht tun.

l008com
quelle
1
Du kennst die Antwort. Warum dann fragen? Es ist unwahrscheinlich, dass Java-Applets oder Flash-Objekte von Benutzern zugelassen werden (möglicherweise nur von Personen, die neu im Internet sind). Daher ist dies im Normalfall keine Lösung. ActiveX und in der Nähe befindliche Inhalte funktionieren nur im Internet Explorer - und daher sind Benutzer anderer Browser nicht betroffen (und darüber hinaus gibt es auch im Internet Explorer eine Sicherheitsrichtlinie, die verhindert, dass Websites böse Dinge tun)
Alma Do,
Meine IP-Adresse wird HTTP_X_FORWARDED_FORauf dieser Seite erfasst.
Tomdemuyt
50
Warum dann fragen? Weil ich vielleicht, nur vielleicht, nicht alles weiß.
1008com
1
Diese Jungs machen es: whatismyproxy.com
likebike
1
@likebike Schön. Schauen Sie sich an, wie sie das machen.
Dominic Cerisano

Antworten:

117

Wie sich herausstellt, ermöglicht die aktuelle WebRTC-Erweiterung von HTML5, dass Javascript die lokale Client-IP-Adresse abfragt. Ein Proof of Concept finden Sie hier: http://net.ipcalf.com

Diese Funktion ist anscheinend beabsichtigt und kein Fehler. Aufgrund seiner kontroversen Natur wäre ich jedoch vorsichtig, mich auf dieses Verhalten zu verlassen. Trotzdem denke ich, dass es perfekt und angemessen auf Ihren beabsichtigten Zweck eingeht (dem Benutzer zu zeigen, was sein Browser leckt).

eine Reise
quelle
1
Das war hilfreich. Danke noch einmal!
Ansuraj Khadanga
7
Es funktioniert nur auf dem Chrom und Firefox, und NICHT auf dem IE, Edge oder Safari
Ali
Ich habe meine WAN-IP nachgeschlagen und diese Website whatismyip.com hat mir auch meine lokale IP gegeben, und ich denke, das hat etwas mit JS zu tun.
Shayan
@ali Sie haben Recht, die oben erwähnte Website kann meine lokale IP auf Edge nicht mitteilen.
Shayan
6
Google Chrome versteckt standardmäßig die lokale IP. Es zeigt etwas Ähnliches wie e87e041d-15e1-4662-adad-7a6601fca9fb.local . Dieses Verhalten kann Änderungen werden durch die variable Einstellung # enable-WebRTC-hide-local-ips-mit-mdns an Behinderten in Chrome: // flags
injaon
81

Aktualisieren

Diese Lösung würde nicht mehr funktionieren, da Browser das Webrtc-Leck beheben: Weitere Informationen hierzu finden Sie in der folgenden Frage: RTCIceCandidate gibt keine IP mehr zurück


Zusätzlich zur Antwort von afourney funktioniert dieser Code in Browsern, die WebRTC (Chrome und Firefox) unterstützen. Ich habe gehört, dass es eine Bewegung gibt, die eine Funktion implementiert, mit der Websites die IP anfordern (wie im Fall des geografischen Standorts oder der Benutzermedien des Benutzers), obwohl sie in keinem dieser Browser noch implementiert werden muss.

Hier ist eine modifizierte Version des Quellcodes , die die Zeilen reduziert und keine Betäubungsanforderungen stellt, da Sie nur die lokale IP und nicht die öffentliche IP möchten:

window.RTCPeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection;//compatibility for Firefox and chrome
var pc = new RTCPeerConnection({iceServers:[]}), noop = function(){};      
pc.createDataChannel('');//create a bogus data channel
pc.createOffer(pc.setLocalDescription.bind(pc), noop);// create offer and set local description
pc.onicecandidate = function(ice)
{
 if (ice && ice.candidate && ice.candidate.candidate)
 {
  var myIP = /([0-9]{1,3}(\.[0-9]{1,3}){3}|[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7})/.exec(ice.candidate.candidate)[1];
  console.log('my IP: ', myIP);   
  pc.onicecandidate = noop;
 }
};

Wir erstellen eine Dummy-Peer-Verbindung, über die der Remote-Peer Kontakt mit uns aufnehmen kann. Wir tauschen im Allgemeinen Eiskandidaten miteinander aus und lesen die Eiskandidaten, die wir der IP des Benutzers mitteilen können.

Eine Demo finden Sie unter -> Demo

mido
quelle
Danke für diesen Mido! Sehr geschätzt.
Sujay Phadke
1
@dampee - Ich glaube, Edge unterstützt derzeit keine Datenkanäle.
MichaelB76
Was ist ein gefälschter Datenkanal? Kann keine Referenz auf Google finden
AmazingTurtle
2
Beachten Sie, dass die API "createOffer" auf Promise anstatt auf successCallback und failCallback als Parameter umgestellt wurde. Dies funktioniert möglicherweise nicht bei neueren Versionen. Siehe: developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/…
Dickeylth
10

Die WebRTC-API kann verwendet werden, um die lokale IP des Clients abzurufen.

Der Browser unterstützt es jedoch möglicherweise nicht oder der Client hat es aus Sicherheitsgründen deaktiviert. Auf jeden Fall sollte man sich langfristig nicht auf diesen "Hack" verlassen, da er wahrscheinlich in Zukunft gepatcht wird (siehe die Antwort von Cullen Fluffy Jennings).

Der folgende ECMAScript 6-Code zeigt, wie das geht.

/* ES6 */
const findLocalIp = (logInfo = true) => new Promise( (resolve, reject) => {
    window.RTCPeerConnection = window.RTCPeerConnection 
                            || window.mozRTCPeerConnection 
                            || window.webkitRTCPeerConnection;

    if ( typeof window.RTCPeerConnection == 'undefined' )
        return reject('WebRTC not supported by browser');

    let pc = new RTCPeerConnection();
    let ips = [];

    pc.createDataChannel("");
    pc.createOffer()
     .then(offer => pc.setLocalDescription(offer))
     .catch(err => reject(err));
    pc.onicecandidate = event => {
        if ( !event || !event.candidate ) {
            // All ICE candidates have been sent.
            if ( ips.length == 0 )
                return reject('WebRTC disabled or restricted by browser');

            return resolve(ips);
        }

        let parts = event.candidate.candidate.split(' ');
        let [base,componentId,protocol,priority,ip,port,,type,...attr] = parts;
        let component = ['rtp', 'rtpc'];

        if ( ! ips.some(e => e == ip) )
            ips.push(ip);

        if ( ! logInfo )
            return;

        console.log(" candidate: " + base.split(':')[1]);
        console.log(" component: " + component[componentId - 1]);
        console.log("  protocol: " + protocol);
        console.log("  priority: " + priority);
        console.log("        ip: " + ip);
        console.log("      port: " + port);
        console.log("      type: " + type);

        if ( attr.length ) {
            console.log("attributes: ");
            for(let i = 0; i < attr.length; i += 2)
                console.log("> " + attr[i] + ": " + attr[i+1]);
        }

        console.log();
    };
} );

Beachten Sie, dass ich schreibe return resolve(..)oder return reject(..)als Abkürzung. Beide Funktionen geben nichts zurück.

Dann haben Sie vielleicht Folgendes:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Local IP</title>
</head>
<body>
    <h1>My local IP is</h1>
    <p id="ip">Loading..</p>
    <script src="ip.js"></script>
    <script>
    let p = document.getElementById('ip');
    findLocalIp().then(
        ips => {
            let s = '';
            ips.forEach( ip => s += ip + '<br>' );
            p.innerHTML = s;
        },
        err => p.innerHTML = err
    );
    </script>
</body>
</html>
Linblow
quelle
9

Ich habe Midos Post aufgeräumt und dann die gefundene Funktion aufgeräumt. Dies wird entweder zurückkehren falseoder ein array. Denken Sie beim Testen daran, dass Sie das Array in der Webentwicklerkonsole reduzieren müssen, da Sie sonst aufgrund seines nicht intuitiven Standardverhaltens möglicherweise glauben, dass es ein leeres Array zurückgibt array.

function ip_local()
{
 var ip = false;
 window.RTCPeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection || false;

 if (window.RTCPeerConnection)
 {
  ip = [];
  var pc = new RTCPeerConnection({iceServers:[]}), noop = function(){};
  pc.createDataChannel('');
  pc.createOffer(pc.setLocalDescription.bind(pc), noop);

  pc.onicecandidate = function(event)
  {
   if (event && event.candidate && event.candidate.candidate)
   {
    var s = event.candidate.candidate.split('\n');
    ip.push(s[0].split(' ')[4]);
   }
  }
 }

 return ip;
}

Denken Sie außerdem daran, dass dies kein Alt-Neu- System wie CSS ist, border-radiusobwohl eines dieser Elemente von IE11 und älteren Versionen überhaupt nicht unterstützt wird. Verwenden Sie immer die Objekterkennung, testen Sie in einigermaßen älteren Browsern (z. B. Firefox 4, IE9, Opera 12.1) und stellen Sie sicher, dass Ihre neueren Skripte Ihre neueren Codebits nicht beschädigen. Zusätzlich immer Standards konformen Code erkennt zuerst so , wenn es etwas mit sagen , ein CSS - Präfix erkennt den Standard nicht-gelegten Code ist zuerst und dann zurückfallen , wie die langfristige Unterstützung wird schließlich für den Rest davon Existenz standardisiert werden.

John
quelle
Sie erklären neu ip- Zeile 3 und Zeile 8.
user2757813
@Anu WebRTC wurde erst eingeführt, als Internet Explorer 15 (oder "Edge 15"), also nein. Aus diesem Grund gibt die Funktion in der vierten Zeile oben false zurück, wenn keines der Objekte vorhanden ist. Wenn es im IE einen anderen Weg gibt, dies zu erreichen, ist mir dies derzeit nicht bekannt.
John
@ John - Wie übergeben wir den Rückgabewert an eine PHP-Variable? Über einen versteckten Beitrag?
MarcoZen
@MarcoZen In <input name="example1" type="hidden" value="whatever" />einer solchen Situation können Sie einen AJAX POST verwenden oder verwenden. Ich empfehle dringend, meine ajax()Funktion hier zu studieren
John
Ich habe gerade herausgefunden, dass einige Browser (z. B. Chrome) jetzt die Bereitstellung der IP blockieren - der gleiche Code wird jetzt in einen mDNS-Hostnamen aufgelöst, wenn keine Video- / Audio-Berechtigung angefordert wird. Siehe groups.google.com/forum/#!topic/discuss-webrtc/6stQXi72BEU
Christoph Bimminger
6

function getUserIP(onNewIP) { //  onNewIp - your listener function for new IPs
  //compatibility for firefox and chrome
  var myPeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection;
  var pc = new myPeerConnection({
      iceServers: []
    }),
    noop = function() {},
    localIPs = {},
    ipRegex = /([0-9]{1,3}(\.[0-9]{1,3}){3}|[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7})/g,
    key;

  function iterateIP(ip) {
    if (!localIPs[ip]) onNewIP(ip);
    localIPs[ip] = true;
  }
  onNewIP
  //create a bogus data channel
  pc.createDataChannel("");

  // create offer and set local description
  pc.createOffer().then(function(sdp) {
    sdp.sdp.split('\n').forEach(function(line) {
      if (line.indexOf('candidate') < 0) return;
      line.match(ipRegex).forEach(iterateIP);
    });

    pc.setLocalDescription(sdp, noop, noop);
  }).catch(function(reason) {
    // An error occurred, so handle the failure to connect
  });

  //listen for candidate events
  pc.onicecandidate = function(ice) {
    if (!ice || !ice.candidate || !ice.candidate.candidate || !ice.candidate.candidate.match(ipRegex)) return;
    ice.candidate.candidate.match(ipRegex).forEach(iterateIP);
  };
}
getUserIP(console.log)

Joaquín Piñeyro
quelle
Bitte verwenden Sie die Editoroptionen, um Ihren Code entsprechend zu formatieren.
31.
3
Es wäre großartig, wenn Sie nicht nur Code ablegen, sondern auch erklären würden, was in seinem und Ihrem Code vor sich geht. Es hilft dem Frageautor und anderen Benutzern. Es ist gut, wenn es funktioniert, aber meiner Meinung nach ist es noch wichtiger zu wissen, warum.
Davejal
irgendwelche IE-kompatiblen Lösungen?
Anu
1
Der Kommentar ist eine Kopie dieses Artikels: ourcodeworld.com/articles/read/257/…
Darkshifty
Ich habe gerade herausgefunden, dass einige Browser (z. B. Chrome) jetzt die Bereitstellung der IP blockieren - der gleiche Code wird jetzt in einen mDNS-Hostnamen aufgelöst, wenn keine Video- / Audio-Berechtigung angefordert wird. Siehe groups.google.com/forum/#!topic/discuss-webrtc/6stQXi72BEU
Christoph Bimminger
5

Chrome 76+

Letztes Jahr habe ich Linblows Antwort (19.10.2018) verwendet, um meine lokale IP über Javascript erfolgreich zu ermitteln. Die jüngsten Chrome-Updates (76?) Haben diese Methode jedoch so verbessert, dass sie jetzt eine verschleierte IP-Adresse zurückgibt, z.1f4712db-ea17-4bcf-a596-105139dfd8bf.local

Wenn Sie die volle Kontrolle über Ihren Browser haben, können Sie dieses Verhalten rückgängig machen, indem Sie es in Chrome Flags deaktivieren und in Ihre Adressleiste eingeben:

chrome://flags

und Deaktivieren der Flagge Anonymize local IPs exposed by WebRTC

In meinem Fall benötige ich die IP für ein TamperMonkey-Skript, um meinen aktuellen Standort zu bestimmen und je nach Standort verschiedene Aktionen auszuführen. Ich habe auch die volle Kontrolle über meine eigenen Browsereinstellungen (keine Unternehmensrichtlinien usw.). Für mich reicht es also aus, die chrome://flagsEinstellung zu ändern .

Quellen:

https://groups.google.com/forum/#!topic/discuss-webrtc/6stQXi72BEU

https://codelabs.developers.google.com/codelabs/webrtc-web/index.html

Cssyphus
quelle
Diese Flagge könnte verschwinden. Derzeit scheinen Erweiterungen immer noch IPs zu erhalten, sodass Sie möglicherweise versuchen können, diese über das Hintergrundskript abzurufen. Langfristig sind jedoch alle Wetten geschlossen.
Philipp Hancke
1
Laut groups.google.com/forum/#!topic/discuss-webrtc/6stQXi72BEU sollte die IP- Adresse weiterhin zurückgegeben werden, wenn Sie Ihre Lösung implementieren, für die eine Audio- / Video-Berechtigung erforderlich ist.
Christoph Bimminger
4

Weitere Informationen darüber, welche Einschränkungen Browser wahrscheinlich hinzufügen werden, um dies zu mildern, und was IETF dagegen unternimmt und warum dies bei IETF SPEC zur IP-Verarbeitung erforderlich ist

Cullen Fluffy Jennings
quelle
0

Ein RTCPeerConnectionkann verwendet werden. In Browsern wie Chrome, in denen eine getUserMediaBerechtigung erforderlich ist , können wir nur verfügbare Eingabegeräte erkennen und anfordern.

const internalIp = async () => {
    if (!RTCPeerConnection) {
        throw new Error("Not supported.")
    }

    const peerConnection = new RTCPeerConnection({ iceServers: [] })

    peerConnection.createDataChannel('')
    peerConnection.createOffer(peerConnection.setLocalDescription.bind(peerConnection), () => { })

    peerConnection.addEventListener("icecandidateerror", (event) => {
        throw new Error(event.errorText)
    })

    return new Promise(async resolve => {
        peerConnection.addEventListener("icecandidate", async ({candidate}) => {
            peerConnection.close()

            if (candidate && candidate.candidate) {
                const result = candidate.candidate.split(" ")[4]
                if (result.endsWith(".local")) {
                    const inputDevices = await navigator.mediaDevices.enumerateDevices()
                    const inputDeviceTypes = inputDevices.map(({ kind }) => kind)

                    const constraints = {}

                    if (inputDeviceTypes.includes("audioinput")) {
                        constraints.audio = true
                    } else if (inputDeviceTypes.includes("videoinput")) {
                        constraints.video = true
                    } else {
                        throw new Error("An audio or video input device is required!")
                    }

                    const mediaStream = await navigator.mediaDevices.getUserMedia(constraints)
                    mediaStream.getTracks().forEach(track => track.stop())
                    resolve(internalIp())
                }
                resolve(result)
            }
        })
    })
}
Richie Bendall
quelle