获取IP地址

前端获取途径

1. 通过webRTC的方式获取

这种方式需要浏览器支持webRTC对象或没有屏蔽webRTC。所以可能部分用户无法使用好处在于可以自控

参考链接:

  1. https://github.com/diafygi/webrtc-ips
// 自执行函数,返回一个函数。
var init = function () {
    var Rpc, rpcInstance, sdp, obj = {}
    var ipArr = []
    var ready = new ReadyObj()
    // 定时器,每10ms执行一次
    var intervalTimer = setInterval(function () {
        if (rpcInstance && rpcInstance.localDescription && rpcInstance.localDescription.sdp && sdp != rpcInstance.localDescription.sdp) {
        	sdp = rpcInstance.localDescription.sdp
        	handleSdp(sdp)
        }
    }, 10)

    function chargeReady() {
        if (!ready.isReady()) {
        	ready.ready()
        	clearInterval(intervalTimer)
        	rpcInstance && rpcInstance.close()
        }
    }

    function t() {
        chargeReady()
    }
    
    /**
    * ip处理
    * @param {String} str ip地址
    */
    function ipToNumber(str) {
        var strArr = str.split('.')
        var t = 0
        var ii = 0
        for (; ii < strArr.length; ii++) {
            t = t << 8 | 255 & parseInt(strArr[ii])
        }
        return t
    }

    /**
        *
        * @param {String} str
        * "v=0
        o=- 2521569421645768096 2 IN IP4 127.0.0.1
        s=-
        t=0 0
        a=group:BUNDLE data
        a=msid-semantic: WMS
        m=application 9 UDP/TLS/RTP/SAVPF 109
        c=IN IP4 0.0.0.0
        b=AS:30
        a=rtcp:9 IN IP4 0.0.0.0
        a=ice-ufrag:U6jO
        a=ice-pwd:ytKYt1YpL4+zB4G0DdlrGDhv
        a=ice-options:trickle
        a=fingerprint:sha-256 D0:67:EE:25:FB:C3:29:7E:0D:57:79:AE:20:68:DA:19:14:53:50:EB:90:B2:FF:93:B3:E4:2D:38:37:A2:77:E2
        a=setup:actpass
        a=mid:data
        a=sendrecv
        a=rtcp-mux
        a=rtpmap:109 google-data/90000
        a=ssrc:1040155820 cname:CeGwDSzmn63xMNZb
        a=ssrc:1040155820 msid:shareinstall shareinstall
        a=ssrc:1040155820 mslabel:shareinstall
        a=ssrc:1040155820 label:shareinstall
        "
        "a=candidate:372587185 1 udp 2113937151 172.18.3.246 52848 typ host generation 0 ufrag U6jO network-cost 50"
    */
    function handleSdp(str) {
        var t, strArr, a, ip, c = str.split('\r\n'),
        ii = 0
        for (; ii < c.length; ii++) {
            t = c[ii]
            strArr = t.split(' ')
            if (0 == t.indexOf('a=candidate:') && (a = strArr[7]) && 'host' == a) {
                ip = strArr[4]
            } else if (0 == t.indexOf('a=rtcp:') && (a = strArr[2]) && 'IP4' == a) {
                ip = strArr[3]
            } else if (0 != t.indexOf('c=') || !(a = strArr[1]) || 'IP4' != a || !(ip = strArr[2])) {
                continue
            }
            if (ip && !obj[ip] && /[0-9]{1,3}(\.[0-9]{1,3}){3}/.test(ip)) {
                if ('0.0.0.0' != ip && 0 != ip.indexOf('127.') && 3758096384 != (4026531840 & ipToNumber(ip))) {
                    obj[ip] = 1
                    ipArr.push(ip)
                }
            }
        }
        if (ipArr.length) {
            chargeReady()
        }
    }

    try {
        Rpc = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection
        if (Rpc) {
            rpcInstance = new Rpc({
                iceServers: []
            }, {
                optional: [{
                    RtpDataChannels: true
                }]
            })
            rpcInstance.onicecandidate = function (e) {
                e.candidate && e.candidate.candidate && handleSdp('a=' + e.candidate.candidate)
            }
            rpcInstance.createDataChannel('shareinstall')
            rpcInstance.createOffer(function (e) {
                try {
                    rpcInstance.setLocalDescription(e, function () {}, t)
                } catch (event) {
                    t(event)
                }
            }, t)
            setTimeout(chargeReady, 2000)
        } else {
            t('not exists')
        }
    } catch (e) {
        t(e)
    }
	return function (callback) {
        ready.run(function () {
            callback(ipArr)
        })
	}
}()
// v() 返回一个function end!!!

init(function (ipArr) {
    return (ipArr || []).join('-')
})

受限于浏览器,可能无法获取ip地址。

2. 通过第三方API解析后获取

这种方式最大的优势是使用他人的成熟方案,但是使用他人的API最大的问题是第三方的服务器宕机后会影响到线上的所有用户。

1. 
$.getJSON('http://www.geoplugin.net/json.gp?jsoncallback=?', function(data) {
	console.log(JSON.stringify(data, null, 2));
});

2.
$.getJSON('//freegeoip.net/json/?callback=?', function(data) {
	console.log(JSON.stringify(data, null, 2));
});

3.
<script src="http://pv.sohu.com/cityjson?ie=utf-8"></script>
<script type="text/javascript">
	// 下面这行和上面的script一起使用  获取真实IP地址
    document.write(returnCitySN["cip"]+','+returnCitySN["cname"] + "真实IP地址")
</script>

4.
http://ip.renfei.net/

5.
这个接口获取ip地址和其他的方式不一致
https://www.taobao.com/help/getip.php

后端获取途径

使用HTTP扩展头部。

X-Forwarded-ForXFF 的内容由「英文逗号 + 空格」隔开的多个部分组成,最开始的是离服务端最远的设备 IP,然后是每一级代理设备的 IP

X-Forwarded-For: client, proxy1, proxy2

X-Real-IP,自定义请求头,X-Real-IP 通常被 HTTP 代理用来表示与它产生 TCP 连接的设备 IP,这个设备可能是其他代理,也可能是真正的请求端。

以上的请求头属性都需要服务器nginx进行配置后才能获取到,默认的请求头中没有。

但是安全问题而言,浏览器插件可以修改请求头的参数,模拟目标IP或者设置虚假IP,因此需要考虑到这样的情况进行防范。

共同的问题

如果浏览器使用翻墙工具,以上的方法都无法获取到用户真正的IP地址。

参考链接:

Koa框架获取用户真实IP

获取请求来源 IP 地址

科普文:如何伪造和获取用户真实 IP ?

获取请求来源 IP 地址