项目中Nginx多级代理是如何获取客户端的真实IP地址


Posted in Servers onMay 30, 2022

多级代理中获取客户端真实IP

日志的格式

nginx中常用日志格式配置如下:

log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                  '$status $body_bytes_sent "$http_referer" '
                  '"$http_user_agent" "$http_x_forwarded_for"';
access_log  /var/log/nginx/access.log  main;

其中的main为日志格式的别名,在使用的时候直接使用别名即可。

例子:

10.0.3.137 - - [09/Oct/2020:09:41:02 +0800] "GET / HTTP/1.0" 304 0 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko" "10.1.9.98"
变量 含义 例子
$remote_addr 客户端的ip地址(直连的IP,代理服务器,显示代理服务ip) 10.0.3.137
$remote_user 用于记录远程客户端的用户名称 -
$time_local 用于记录访问时间和时区 08/Oct/2020:02:37:25 -0400
$request 用于记录请求的url、请求方法,协议的版本 GET / HTTP/1.1
$status 响应状态码 200
$body_bytes_sent 给客户端发送的文件主体内容字节 0
$http_referer 可以记录用户是从哪个链接访问过来的 -
$http_user_agent 用户所使用的代理(一般为浏览器) Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
$http_x_forwarded_for 可以记录客户端IP和所有经过的代理服务器的IP 10.1.9.98

日积月累下,日志文件会越来越大,日志文件太大严重影响服务器效率,所以需要定时对日志文件进行切割。

由于这里是演示,所以切割方式是按分钟来切割,正常生产上使用一般是按天来进行分割:

#!/bin/bash
#日志文件存放目录
LOGS_PATH=/usr/local/nginx/logs
#备份文件名称
YESTERDAY=$(date -d "yesterday" +%Y%m%d%H%M)
#重命名日志文件
mv ${LOGS_PATH}/access.log ${LOGS_PATH}/access_${YESTERDAY}.log
mv ${LOGS_PATH}/error.log ${LOGS_PATH}/error_${YESTERDAY}.log
## 向 Nginx 主进程发送 USR1 信号。USR1 信号是重新打开日志文件
kill -USR1 $(cat /usr/local/nginx/logs/nginx.pid)

然后添加定时任务:

# crontab -e
*/1 * * * * /bin/bash /usr/local/nginx/logs/nginx_log.sh

获取客户端真实IP

服务器资源分配情况如下:

  • 10.1.9.98:充当客户端
  • 10.0.3.137:一级代理
  • 10.0.4.105:二级代理
  • 10.0.4.129:三级代理
  • 10.0.4.120:服务器端,为了方便,这里使用一个nginx充当服务器端,正常情况下一般是一个web服务器,如tomcat。

各个服务初始配置如下:

10.0.3.137的配置:

worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;
    log_format main '$remote_addr - $http_x_forwarded_for - $http_x_real_ip';
    access_log  logs/access.log  main;
    server {
        listen  80;

        location / {
                # proxy_set_header X-Real-IP $remote_addr;
                # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_pass http://10.0.4.105;
        }
    }

}

10.0.4.105的配置,其他配置与10.0.3.137的一致:

...
        location / {
                # proxy_set_header X-Real-IP $remote_addr;
                # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_pass http://10.0.4.129;
        }
...

10.0.4.129的配置,其他配置与10.0.3.137的一致:

...
        location / {
                # proxy_set_header X-Real-IP $remote_addr;
                # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_pass http://10.0.4.120;
        }
...

10.0.4.120的配置,其他配置与10.0.3.137的一致

...
        location / {
                root html;
                index index.html;
        }
...

下面的记录为access.log中打印的结果:

操作 10.0.3.137 10.0.4.105 10.0.4.129 10.0.4.120
10.1.9.98访问curl http://10.0.3.137 10.1.9.98 - - - - 10.0.3.137 - - - - 10.0.4.105 - - - - 10.0.4.129 - - - -
10.0.3.137开启X-Forwarded-For 10.1.9.98 - - - - 10.0.3.137 - 10.1.9.98 - - 10.0.4.105 - 10.1.9.98 - - 10.0.4.129 - 10.1.9.98 - -
10.0.4.105开启X-Forwarded-For 10.1.9.98 - - - - 10.0.3.137 - 10.1.9.98 - - 10.0.4.105 - 10.1.9.98, 10.0.3.137 - - 10.0.4.129 - 10.1.9.98, 10.0.3.137 - -
10.0.4.129开启X-Forwarded-For 10.1.9.98 - - - - 10.0.3.137 - 10.1.9.98 - - 10.0.4.105 - 10.1.9.98, 10.0.3.137 - - 10.0.4.129 - 10.1.9.98, 10.0.3.137, 10.0.4.105 - -
10.1.9.98伪造头部访问curl http://10.0.3.137 -H ‘X-Forwarded-For: 1.1.1.1’ 10.1.9.98 - 1.1.1.1 - - 10.0.3.137 - 1.1.1.1, 10.1.9.98 - - 10.0.4.105 - 1.1.1.1, 10.1.9.98, 10.0.3.137 - - 10.0.4.129 - 1.1.1.1, 10.1.9.98, 10.0.3.137, 10.0.4.105 - -
10.0.3.137开启X-Real-IP 10.1.9.98 - - - - 10.0.3.137 - 10.1.9.98 - 10.1.9.98 10.0.4.105 - 10.1.9.98, 10.0.3.137 - 10.1.9.98 10.0.4.129 - 10.1.9.98, 10.0.3.137, 10.0.4.105 - 10.1.9.98
10.0.4.105开启X-Real-IP 10.1.9.98 - - - - 10.0.3.137 - 10.1.9.98 - 10.1.9.98 10.0.4.105 - 10.1.9.98, 10.0.3.137 - 10.0.3.137 10.0.4.129 - 10.1.9.98, 10.0.3.137, 10.0.4.105 - 10.0.3.137
10.0.4.129开启X-Real-IP 10.1.9.98 - - - - 10.0.3.137 - 10.1.9.98 - 10.1.9.98 10.0.4.105 - 10.1.9.98, 10.0.3.137 - 10.0.3.137 10.0.4.129 - 10.1.9.98, 10.0.3.137, 10.0.4.105 - 10.0.4.105
10.1.9.98伪造头部访问 curl http://10.0.3.137 -H ‘X-Real-IP: 8.8.8.8’ 10.1.9.98 - - - 8.8.8.8 10.0.3.137 - 10.1.9.98 - 10.1.9.98 10.0.4.105 - 10.1.9.98, 10.0.3.137 - 10.0.3.137 10.0.4.129 - 10.1.9.98, 10.0.3.137, 10.0.4.105 - 10.0.4.105

总结:

  • X-Forwarded-For是一个追加的过程,后面的代理会把前面代理的IP追加到X-Forwarded-For尾部,用逗号进行分隔。
  • 应用服务器(10.0.4.120)无法从X-Forwarded-For中获取到与它直连的代理服务器的IP(10.0.4.129),此时我们可以使用r e m o t e a d d r ( 远 程 i p , 表 示 直 连 的 那 台 代 理 ) 。 当 服 务 器 无 法 过 remote_addr(远程ip,表示直连的那台代理)。当服务器无法过remote addr(远程ip,表示直连的那台代理)。当服务器无法过http_x_forwarded_for获得上级代理或者客户端的ip时(可能没有经过代理),应该使用$remote_addr。
  • 在代理过程中至少有一个代理设置了X-Forwarded-For,否则后面的代理或者应用服务器无法获得相关信息。
  • X-Forwarded-For中虽然包含了真实的客户端IP,一般是第一个IP,但是如果客户端伪造了请求头,那么真实的客户端IP就不是第一个了。
  • HTTP中header里面的X-Real-IP只是一个变量,后面的设置会覆盖前面的设置,所以只需要在第一个代理服务器上设置proxy_set_header X-Real-IP $remote_addr即可,然后在应用端直接引用$http_x_real_ip就行。

在java中,如果请求没有经过nginx代理,可以使用如下方法获取客户端的真实IP:

# 类似nginx中的$remote_addr
request.getRemoteHost();

如果请求经过了nginx代理,可以从请求头中获取(前提是必须正确配置nginx才能获取到):

request.getHeader("x-real-ip");

如果是用的其他Apache,Squid等反向代理软件,同样是从请求头中获取真实IP,只是属性名不一样而已。

到此这篇关于项目中Nginx多级代理是如何获取客户端的真实IP地址的文章就介绍到这了!


Tags in this post...

Servers 相关文章推荐
详解如何修改nginx的默认端口
Mar 31 Servers
nginx常用命令放入shell脚本详解
Mar 31 Servers
Apache POI的基本使用详解
Nov 07 Servers
Apache Hudi集成Spark SQL操作hide表
Mar 31 Servers
深入解析Apache Hudi内核文件标记机制
Mar 31 Servers
Linux、ubuntu系统下查看显卡型号、显卡信息详解
Apr 07 Servers
在Docker容器中部署SQL Server
Apr 11 Servers
Windows Server 2016 配置 IIS 的详细步骤
Apr 28 Servers
Docker与K8s关系介绍不会Docker也可以使用K8s
Jun 25 Servers
windows系统安装配置nginx环境
Jun 28 Servers
nginx静态资源的服务器配置方法
Jul 07 Servers
ubuntu如何搭建vsftpd服务器
Dec 24 Servers
nginx rewrite功能使用场景分析
May 30 #Servers
Nginx静态压缩和代码压缩提高访问速度详解
May 30 #Servers
Nginx 配置 HTTPS的详细过程
May 30 #Servers
关于windows server 2012 DC 环境 重启后蓝屏代码:0xc00002e2的问题
May 25 #Servers
聊聊配置 Nginx 访问与错误日志的问题
May 25 #Servers
利用nginx搭建RTMP视频点播、直播、HLS服务器
详解Nginx的超时keeplive_timeout配置步骤
May 25 #Servers
You might like
PHP转换文件夹下所有文件编码的实现代码
2013/06/06 PHP
php上传图片类及用法示例
2016/05/11 PHP
浅谈PHP面向对象之访问者模式+组合模式
2017/05/22 PHP
Jquery工作常用实例 使用AJAX使网页进行异步更新
2011/07/26 Javascript
JavaScript高级程序设计(第3版)学习笔记8 js函数(中)
2012/10/11 Javascript
JS的location.href跳出框架打开新页面的方法
2014/09/04 Javascript
JS动态加载当前时间的方法
2015/02/09 Javascript
jQuery Validate插件实现表单验证
2016/08/19 Javascript
简单分析javascript中的函数
2016/09/10 Javascript
JS/jquery实现一个网页内同时调用多个倒计时的方法
2017/04/27 jQuery
javascript数组拍平方法总结
2018/01/20 Javascript
详解vue项目中调用百度地图API使用方法
2019/04/25 Javascript
vue里的data要用return返回的原因浅析
2019/05/28 Javascript
在vue中使用axios实现post方式获取二进制流下载文件(实例代码)
2019/12/16 Javascript
封装一下vue中的axios示例代码详解
2020/02/16 Javascript
jQuery中event.target和this的区别详解
2020/08/13 jQuery
[01:04:29]DOTA2-DPC中国联赛 正赛 Phoenix vs XG BO3 第二场 1月31日
2021/03/11 DOTA
Python序列之list和tuple常用方法以及注意事项
2015/01/09 Python
在Python中使用SQLite的简单教程
2015/04/29 Python
python中argparse模块用法实例详解
2015/06/03 Python
详解python3百度指数抓取实例
2016/12/12 Python
python实现字符串和字典的转换
2018/09/29 Python
使用bandit对目标python代码进行安全函数扫描的案例分析
2021/01/27 Python
利用HTML5中Geolocation获取地理位置调用Google Map API在Google Map上定位
2013/01/23 HTML / CSS
HTML5触摸事件(touchstart、touchmove和touchend)的实现
2020/05/08 HTML / CSS
巴西化妆品商店:Lojas Rede
2019/07/26 全球购物
估算杭州有多少软件工程师
2015/08/11 面试题
大学毕业生自我鉴定
2013/11/05 职场文书
军训拉歌口号
2014/06/13 职场文书
个人房屋转让协议书范本
2014/10/26 职场文书
新闻稿件写作技巧
2015/07/18 职场文书
车辆管理制度范本
2015/08/05 职场文书
大学生自我鉴定怎么写
2019/05/07 职场文书
python基于scrapy爬取京东笔记本电脑数据并进行简单处理和分析
2021/04/14 Python
详解MySQL连接挂死的原因
2021/05/18 MySQL
Python OpenCV超详细讲解调整大小与图像操作的实现
2022/04/02 Python