互联网产品获取真实用户ip需求分析与技术实现

Wed Nov 27, 2019

200 Words|Read in about 1 Min
Tags: Devops  

很多互联网产品在某些地方需要展示用户ip场景的时候,有这样的一个需求需要相应的系统能获取到用户真实的ip。这个需求非常非常普遍,非常非常多。
但是很多人都没有理解到什么是“真实”ip和真正需要的ip以及解决方案。

需求:获取用户真实ip

  • 需要在系统后台展示用户真实的ip,或者做一些业务、安全上面的策略

    解决方法:

    传统解决方案

    1.http 请求头里面的字段remote_addr、X-Forwarded-For、HTTP_CLIENT_IP等。
    2.中间经过层层代理,比如CDN、Nginx、Haproxy、Squid、Varnish等,通过运维设置X-Forward-For全部包装在一起。
    3.后端拿到X-Forward-For可能是一串,也可能是负载均衡的地址(F5、Haproxy、Nginx等,通过一系列设置可以将TCP ES地址转换强制塞在X-ForWard-For里面),然后研发人员展示这个所谓“真实的ip”。
    4.使用Remote Address 无法伪造,因为建立 TCP 连接需要三次握手,如果伪造了源 IP,无法建立 TCP 连接,更不会有后面的 HTTP 请求。[但是并不是所有连接都是直接连接业务tcp端口,一般是负载均衡]
    5.通过cdn转发自定义header。

    传统缺点:

    1.http请求header的X系列字段不可靠,并不信任。也是非标准的

    这样就可以轻易更改或者插入里面的内容
    curl -H 'X-Forwarded-For: 8.8.8.8,1.2.3.4' http://10.0.0.127:8000
    {
    "ip.HTTP_X_FORWARDED_FOR": "8.8.8.8,1.2.3.4"
    }
    

    X-Forwarded-For 是一个 HTTP 扩展头部。HTTP/1.1(RFC 2616)协议并没有对它的定义,它最开始是由 Squid 这个缓存代理软件引入,用来表示 HTTP 请求端真实 IP。 如今它已经成为事实上的标准,被各大 HTTP 代理、负载均衡等转发服务广泛使用,并被写入 RFC 7239(Forwarded HTTP Extension)标准之中。
    (注意是应用层http/https代理具有这样功能,但是TCP 4层的代理转发是没有这样的功能)
    2.TCP L4的负载均衡不支持远端ip透传进入业务集群的Ingress服务。 (若TCP 这样的负载均衡需要转发这样的头信息,需要使用ProxyProtocol协议。
    比如Haproxy、nginx都需要特殊编译参数然后打开。与之匹配开启ProxyProtocol功能。)

    3.使用[Remote Address]是在生产环境中,基本上不可能的。
    基本上没有业务服务器直接绑定一个公网ip、一台服务器一台业务、一个nginx进行业务部署。

    因为建立 TCP 连接需要三次握手的ip基本上是负载均衡设备或者Ingress(ingress-Nginx、Haproxy、squid、Istio Gateway等)所以Remote Address=负载均衡的内部路由可达接口ip地址。
    加上在nginx、haproxy上设置下面类似的配置
    来将http请求头中的[Remote Address]自动转换插入到http请求头的X-Forwarded-For中:

    proxy_set_header X-Real-IP $remote_addr;
    roxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    
    

结果就是: X-Forwarded-For: client, proxy1, proxy2
X-Real-IP:proxy2 其实这两个字段也是可以轻易改掉的,包括cdn自定义header:

curl http://test.sklinux.com/ -H 'X-Forwarded-For: 1.1.1.1' -H 'X-Real-IP: 2.2.2.2'

改进解决方案

1.通过端上进行主动上报,上报方式可以加密,也可以用加密body,也可以直接socket传。细节就不讲了,ios、andriod、web、h5手法很多。这种方法获取的ip真实有效,可信度基本上可以达到(90%以上,而且不能伪造,但是能否一个ip就代表了一个用户呢?不是)
2.tcp层的负载均衡双向打开ProxyProtocol转到后端,只能转发一定程度上的“真实”用户ip。(并不一定可靠,而且可能是篡改过的)

用户的真实IP从何而来

1.宽带供应商提供独立IP。比如家里电信宽带上网,电信给分配了公网ip。
2.宽带供应商不能提供独立IP。可能栋楼就一个或者几个公网出口ip。
3.手机2g上网,多层内部代理层层转发最后出口做出口动态NAT。
4.人数众多的办公室通过NAT动态NAT出口ip负载均衡。

总之,后端服务去获取最前端用户的真实ip在移动互联网越来越困难,毕竟前后端离的太远。
用大前端的手法,边缘计算,然后汇聚提交给后端服务的方法是未来趋势!

See Also

Wed Nov 27, 2019

200 Words|Read in about 1 Min
Tags: Devops