项目中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
Linux中Nginx的防盗链和优化的实现代码
Jun 20 Servers
Nginx实现负载均衡的项目实践
Mar 18 Servers
iSCSI服务器CHAP双向认证配置
Apr 01 Servers
tomcat正常启动但网页却无法访问的几种解决方法
May 06 Servers
Nginx静态压缩和代码压缩提高访问速度详解
May 30 Servers
Zabbix对Kafka topic积压数据监控的问题(bug优化)
Jul 07 Servers
Docker部署Mysql8的实现步骤
Jul 07 Servers
Nginx代理Redis哨兵主从配置的实现
Jul 15 Servers
码云(gitee)通过git自动同步到阿里云服务器
Dec 24 Servers
ubuntu端向日葵键盘输入卡顿问题及解决
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 字符串分割和比较
2009/10/06 PHP
理解php原理的opcodes(操作码)
2010/10/26 PHP
Yii2框架视图(View)操作及Layout的使用方法分析
2019/05/27 PHP
Nigma vs Liquid BO3 第二场2.13
2021/03/10 DOTA
Javascript里使用Dom操作Xml
2007/01/22 Javascript
js 获取屏幕各种宽高的方法(浏览器兼容)
2013/05/15 Javascript
js数组循环遍历数组内所有元素的方法
2014/01/18 Javascript
原生js实现fadein 和 fadeout淡入淡出效果
2014/06/05 Javascript
JavaScript使用focus()设置焦点失败的解决方法
2014/09/03 Javascript
JS实现仿google、百度搜索框输入信息智能提示的实现方法
2015/04/20 Javascript
js实现的tab标签切换效果代码分享
2015/08/25 Javascript
详解JavaScript中的4种类型识别方法
2015/09/14 Javascript
Bootstrap Chart组件使用教程
2016/04/28 Javascript
JS实现鼠标框选效果完整实例
2016/06/20 Javascript
微信小程序 数据封装,参数传值等经验分享
2017/01/09 Javascript
angularjs实现多张图片上传并预览功能
2017/02/24 Javascript
vue+springboot前后端分离实现单点登录跨域问题解决方法
2018/01/30 Javascript
通过jquery.cookie.js实现记住用户名、密码登录功能
2018/06/20 jQuery
[46:20]DOTA2-DPC中国联赛 正赛 PSG.LGD vs LBZS BO3 第二场 1月22日
2021/03/11 DOTA
windows7 32、64位下python爬虫框架scrapy环境的搭建方法
2018/11/29 Python
使用Python将Mysql的查询数据导出到文件的方法
2019/02/25 Python
django连接oracle时setting 配置方法
2019/08/29 Python
python下载库的步骤方法
2019/10/12 Python
python GUI库图形界面开发之PyQt5窗口控件QWidget详细使用方法
2020/02/26 Python
TensorFlow2.X结合OpenCV 实现手势识别功能
2020/04/08 Python
Python 通过爬虫实现GitHub网页的模拟登录的示例代码
2020/08/17 Python
中国跨境电商:Tomtop
2017/03/16 全球购物
正宗的日本零食和糖果订阅盒:Bokksu
2019/11/21 全球购物
作风整顿个人剖析材料
2014/10/06 职场文书
金正昆讲礼仪观后感
2015/06/11 职场文书
幼儿园小班教师随笔
2015/08/14 职场文书
大学学习委员竞选稿
2015/11/20 职场文书
《孙子兵法》:欲成大事者,需读懂这些致胜策略
2019/08/23 职场文书
python 破解加密zip文件的密码
2021/04/22 Python
Mysql数据库按时间点恢复实战记录
2021/06/30 MySQL
正则表达式拆分url实例代码
2022/02/24 Java/Android