项目中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 比 Apache 更牛逼
Mar 31 Servers
Mac环境Nginx配置和访问本地静态资源的实现
Mar 31 Servers
Nginx缓存设置案例详解
Sep 15 Servers
教你快速构建一个基于nginx的web集群项目
Nov 27 Servers
nginx共享内存的机制详解
Mar 21 Servers
Nginx配置根据url参数重定向
Apr 11 Servers
nginx lua 操作 mysql
May 15 Servers
教你如何用cmd快速登录服务器
Jun 10 Servers
Windows server 2022创建创建林、域树、子域的步骤
Jun 25 Servers
nginx七层负载均衡配置详解
Jul 15 Servers
Nginx代理Redis哨兵主从配置的实现
Jul 15 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
实用函数5
2007/11/08 PHP
php实现上传图片生成缩略图示例
2014/04/13 PHP
Nginx下配置codeigniter框架方法
2015/04/07 PHP
php错误日志简单配置方法
2016/07/11 PHP
IE和Firefox在JavaScript应用中的兼容性探讨
2008/04/01 Javascript
不懂JavaScript应该怎样学
2008/04/16 Javascript
从数据结构分析看:用for each...in 比 for...in 要快些
2013/04/17 Javascript
javascript比较两个日期的先后示例代码
2014/12/31 Javascript
html的DOM中Event对象onblur事件用法实例
2015/01/21 Javascript
JavaScript实现动画打开半透明提示层的方法
2015/04/21 Javascript
JavaScript实现快速排序的方法
2015/07/31 Javascript
jQuery实现的给图片点赞+1动画效果(附在线演示及demo源码下载)
2015/12/31 Javascript
理解Angular数据双向绑定
2016/01/10 Javascript
基于javascript实现全屏漂浮广告
2016/03/31 Javascript
JS简单获取当前日期时间的方法(如:2017-03-29 11:41:10 星期四)
2017/03/29 Javascript
详解vue-router基本使用
2017/04/18 Javascript
解决Vue.js 2.0 有时双向绑定img src属性失败的问题
2018/03/14 Javascript
[03:00]DOTA2-DPC中国联赛1月18日Recap集锦
2021/03/11 DOTA
python算法学习之计数排序实例
2013/12/18 Python
Python使用matplotlib实现的图像读取、切割裁剪功能示例
2018/04/28 Python
Python matplotlib以日期为x轴作图代码实例
2019/11/22 Python
使用python批量转换文件编码为UTF-8的实现
2020/04/03 Python
pandas分组聚合详解
2020/04/10 Python
python转化excel数字日期为标准日期操作
2020/07/14 Python
丝芙兰新加坡官网:Sephora新加坡
2018/12/04 全球购物
StubHub新西兰:购买和出售你的门票
2019/04/22 全球购物
.TTL是什么?有什么用处,通常那些工具会用到它?(ping? traceroute? ifconfig? netstat?)
2016/05/09 面试题
一年级班主任感言
2014/03/08 职场文书
讲座主持词
2014/03/20 职场文书
2014年业务工作总结
2014/11/17 职场文书
2014年人事行政工作总结
2014/12/03 职场文书
2015年企业新年寄语
2014/12/08 职场文书
2015年音乐教师个人工作总结
2015/05/20 职场文书
干部培训工作总结2015
2015/05/25 职场文书
毕业答辩开场白范文
2015/05/27 职场文书
Python编程编写完善的命令行工具
2021/09/15 Python