博客:
背景资料
由于产品需求,应用端必须获取真实的客户端IP。 访问链接如下:
由于应用经过了多个代理,默认无法获取真实IP。
基本概念
在实现之前,我们先简单了解一下常用的一些获取IP的方法。
(1)
代表客户端IP,但其值不是由客户端提供,而是由服务器根据客户端IP指定。 当您不通过任何代理访问应用程序时,应用程序获取的是您的主机IP。 如果过程中转发了代理,正常情况下应用程序会获取代理的IP,除非该地址在代理服务器上手动设置为您的主机IP。
(2)X--对于
X--For是HTTP扩展头,简称XFF。
XFF的内容由“英文逗号+空格”分隔的多个部分组成。 首先是距离服务器最远的设备的IP,然后是各级代理设备的IP。 格式为:X--表示:,,。
!! PS:X--For的格式是可以伪造的。
如果一个应用程序前面有三个代理:对于:IP0,IP1,IP2。 这里没有IP3,因为它是转发代理。 转发过程中,IP地址会被追加到XFF后面,你自己的IP地址也会放进去。
!! PS:前一个节点的IP只有通过代理才会添加到XFF中。
(3)X-Real-IP
X-Real-IP 是一个自定义标头字段,通常由 HTTP 代理用来指示与其生成 TCP 连接的设备的 IP。 与XFF不同,它不是列表,记录不能追加到IP的X-Real-末尾,而是直接替换。
理想情况下,我们需要达到以下结果:
也就是说应用程序获取到的X-Real-IP就是客户端的真实IP。 这就要求除了第一层代理外,后续代理不需要设置X-Real-IP,只需要转发即可。 这样应用程序就可以获得真实的客户端访问IP。
执行
由于实际情况,我们会在SLB上做很多规则配置,所以SLB第一层是纯TCP代理,所以不需要在SLB上做太多额外的配置,客户端IP就可以了直接透传。
当请求到达时,需要将客户端IP添加到XFF中,并将X-Real-IP设置为客户端IP。 具体配置如下:
defaults
mode http
log global
option httplog
option dontlog
option http-server-close
log 127.0.0.1 local3
option forwardfor except 127.0.0.0/8
option redispatch
retries 3
timeout http-request 10s
timeout queue 1m
timeout connect 10s
timeout client 5m
timeout server 5m
timeout http-keep-alive 10s
timeout check 10s
unique-id-format %{+X}o\ %ci%cp%fi%fp%Ts%rt%pid
frontend https_link_ha
bind *:443 ssl crt /usr/local/etc/haproxy/cert/crt/ ca-file /usr/local/etc/haproxy/cert/ca/ca.pem verify optional
#log 127.0.0.1 local3
mode http
log-format "%ID %ci:%cp [%tr] %ft %b/%s %TR/%Tw/%Tc/%Tr/%Ta %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r"
option accept-invalid-http-request
http-request set-header x-request-id %[unique-id]
http-request set-header x-request-time %[date()]
http-request set-header X-Real-IP %[src]
default_backend pre
backend pre
server 1 10.74.136.13:8080 check inter 1500 rise 3 fall 3 weight 3
主要有两种配置:
现在请求已经到达。
它也是一个代理层。 之前的客户端IP已经放到了XFF中,但是默认情况下,XFF是不启用的。
要在上使用XFF,需要使用以下三个参数:
因此,我们只需要在Nginx中添加以下两个配置即可:
use-forwarded-headers: 'true'
compute-full-forwarded-for: 'true'
配置完成后,Nginx会自动重新加载服务,不需要单独重启。
然后就可以在应用日志中获取客户端的真实IP。
当然,并不是所有场景都可以通过XFF获取用户的真实IP。 例如,当SLB前面有CDN时,可以获取该CDN的源IP。
最后,请大家注意。 如果您想阅读更多优质原创文章,请关注我们的公众号“运维发展故事”。
如果我的文章对您有帮助,请帮助我。 您的支持将鼓励我写出更高质量的文章。 非常感谢!
您还可以将我的公众号设为“明星”,这样当公众号文章更新时,您会第一时间收到推送消息,避免错过我的文章更新。