• 使用Nginx后如何在web应用中获取用户ip及原理解释


    1、问题背景

          在实际应用中,我们可能需要获取用户的ip地址,比如做异地登陆的判断,或者统计ip访问次数等,通常情况下我们使用request.getRemoteAddr()就可以获取到客户端ip,但是当我们使用了nginx作为反向代理后,使用request.getRemoteAddr()获取到的就一直是nginx服务器的ip的地址,那这时应该怎么办?

    2、解决方案

    2.1 part1

    通过 X-real-ip $remote_addr;

    “经过反向代理后,由于在客户端和web服务器之间增加了中间层,因此web服务器无法直接拿到客户端的ip,通过$remote_addr变量拿到的将是反向代理服务器的ip地址”。这句话的意思是说,当你使用了nginx反向服务器后,在web端使用request.getRemoteAddr()(本质上就是获取$remote_addr),取得的是nginx的地址,即$remote_addr变量中封装的是nginx的地址,当然是没法获得用户的真实ip的,但是,nginx是可以获得用户的真实ip的,也就是说nginx使用$remote_addr变量时获得的是用户的真实ip,如果我们想要在web端获得用户的真实ip,就必须在nginx这里作一个赋值操作,如下:

    proxy_set_header    X-real-ip   $remote_addr;

    其中这个X-real-ip是一个自定义的变量名,名字可以随意取,这样做完之后,用户的真实ip就被放在X-real-ip这个变量里了,然后,在web端可以这样获取:request.getAttribute("X-real-ip"),这样就明白了吧。

    当一个请求通过多个代理服务器时,用户的IP将会被代理服务器IP覆盖

    1. #在第一个代理服务器中设置
    2. set x_real_ip=$remote_addr
    3. #最后一个代理服务器中获取
    4. $x_real_ip=IP1

    2.2 part2

    通过 X-Forwarded-For $proxy_add_x_forwarded_for

    2.2.1  $http_x_forwarded_for :

    我们先看看这里有个X-Forwarded-For变量,这是一个squid开发的,用于识别通过HTTP代理或负载平衡器原始IP一个连接到Web服务器的客户机地址的非rfc标准,如果有做X-Forwarded-For设置的话,每次经过proxy转发都会有记录,格式就是client1, proxy1, proxy2,以逗号隔开各个地址,由于他是非rfc标准,所以默认是没有的,需要强制添加,在默认情况下经过proxy转发的请求,在后端看来远程地址都是proxy端的ip 。也就是说在默认情况下我们使用request.getHeader("X-Forwarded-For")获取不到用户的ip,如果我们想要通过这个变量获得用户的ip,我们需要自己在nginx添加如下配置:

    X-Forwarded-For $proxy_add_x_forwarded_for:

    意思是增加一个$proxy_add_x_forwarded_for到X-Forwarded-For里去,注意是增加,而不是覆盖,当然由于默认的X-Forwarded-For值是空的,所以我们总感觉X-Forwarded-For的值就等于$proxy_add_x_forwarded_for的值,实际上当你搭建两台nginx在不同的ip上,并且都使用了这段配置,那你会发现在web服务器端通过request.getHeader("X-Forwarded-For")获得的将会是客户端ip和第一台nginx的ip。

    $proxy_add_x_forwarded_for变量包含客户端请求头中的"X-Forwarded-For",与$remote_addr两部分,他们之间用逗号分开。

    举个例子,有一个web应用,在它之前通过了两个nginx转发, 即用户访问该web通过两台nginx。

    在第一台nginx中,使用
    proxy_set_header            X-Forwarded-For $proxy_add_x_forwarded_for;
    现在的$proxy_add_x_forwarded_for变量的"X-Forwarded-For"部分是空的,所以只有$remote_addr,而$remote_addr的值是用户的ip,于是赋值以后,X-Forwarded-For变量的值就是用户的真实的ip地址了。(总结就是获得了客户端的IP

    到了第二台nginx,使用
    proxy_set_header            X-Forwarded-For $proxy_add_x_forwarded_for;
    现在的$proxy_add_x_forwarded_for变量,X-Forwarded-For部分包含的是用户的真实ip,$remote_addr部分的值是上一台nginx的ip地址,于是通过这个赋值以后现在的X-Forwarded-For的值就变成了“用户的真实ip,第一台nginx的ip。(总结就是第二台获取到了第一台IP和客户端的IP

    3、举个例子说明

    3.1  nginx 配置如下

    1. 192.168.179.99->192.168.179.100->192.168.179.101->192.168.179.102102为最后的服务端)
    2. 192.168.179.99配置
    3. location /{
    4. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    5. proxy_pass http://192.168.179.100;
    6. }
    7. 192.168.179.100配置
    8. location /{
    9. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    10. proxy_pass http://192.168.179.101;
    11. }
    12. 192.168.179.101配置
    13. location /{
    14. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    15. proxy_pass http://192.168.179.102;
    16. }
    17. 192.168.179.102配置
    18. 在日志中设置打印$http_x_forwarded_for,进行观察
    19. log_format main '$http_x_forwarded_for|$http_x_real_ip|$remote_addr - $remote_user [$time_local] "$request" '
    20. '$status $body_bytes_sent "$http_referer" '
    21. '"$http_user_agent" "$http_x_forwarded_for"';

    3.2  请求nginx

    1. (1)客户端使用浏览器去访问192.168.179.99服务端192.168.179.102日志如下,可以看到获取到客户端的IP为192.168.179.4
    2. 192.168.179.4, 192.168.179.99, 192.168.179.100|-|192.168.179.101 - - [26/Apr/2020:10:57:22 +0800] "GET / HTTP/1.0" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.122 Safari/537.36" "192.168.179.4, 192.168.179.99, 192.168.179.100"
    3. 2)客户端192.168.179.103去访问192.168.179.99服务端192.168.179.102日志如下,可以看到获取到客户端的IP为192.168.179.103
    4. 192.168.179.103, 192.168.179.99, 192.168.179.100|-|192.168.179.101 - - [26/Apr/2020:10:57:32 +0800] "GET / HTTP/1.0" 200 4833 "-" "curl/7.29.0" "192.168.179.103, 192.168.179.99, 192.168.179.100"

    4、总结 

    可以看到获取客户端的IP地址不仅可以通过proxy_set_header    X-real-ip $remote_addr;获取到。也可以通过proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;

  • 相关阅读:
    x86: perf_events内核初始化
    nSum问题解题套路4.5-4.6
    结合CAP理论分析ElasticSearch的分布式实现方式
    tensorflow-gpu版本安装及深度神经网络训练与cpu版本对比
    Python编写告警信息,整合Alertmanager告警
    pytest-xdist分布式测试原理浅析
    四类取整方式
    包含漏洞的str_replace函数绕过
    GPT SOVITS项目 一分钟克隆 (文字输出)
    以数字技术赋能产业金融生态能力建设,破解银行的场景焦虑
  • 原文地址:https://blog.csdn.net/yh250648050/article/details/134020247