项目中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
详解Apache SkyWalking 告警配置指南
Apr 22 Servers
Apache POI的基本使用详解
Nov 07 Servers
NGINX 权限控制文件预览和下载的实现原理
Jan 18 Servers
Nginx禁止ip访问或非法域名访问
Apr 07 Servers
Tomcat starup.bat 脚本实现开机自启动
Apr 20 Servers
在容器中使用nginx搭建上传下载服务器
May 11 Servers
windows server 2016 域环境搭建的方法步骤(图文)
Jun 25 Servers
windows系统安装配置nginx环境
Jun 28 Servers
Zabbix对Kafka topic积压数据监控的解决方案
Jul 07 Servers
Docker安装MySql8并远程访问的实现
Jul 07 Servers
ssh服务器拒绝了密码 请再试一次已解决(亲测有效)
Aug 14 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 使用header函数设置HTTP头的示例解析 表头
2013/06/17 PHP
php基于Fleaphp框架实现cvs数据导入MySQL的方法
2016/02/23 PHP
PHP身份证校验码计算方法
2016/08/10 PHP
PHP实现四种基础排序算法的运行时间比较(推荐)
2016/08/11 PHP
thinkPHP框架RBAC实现原理分析
2019/02/01 PHP
Aster vs KG BO3 第二场2.18
2021/03/10 DOTA
CLASS_CONFUSION JS混淆 全源码
2007/12/12 Javascript
jQuery :nth-child前有无空格的区别分析
2011/07/11 Javascript
jQuery .attr()和.removeAttr()方法操作元素属性示例
2013/07/16 Javascript
js控制页面控件隐藏显示的两种方法介绍
2013/10/09 Javascript
Vue.js学习笔记之 helloworld
2016/08/14 Javascript
浅谈Web页面向后台提交数据的方式和选择
2016/09/23 Javascript
Javascript中 toFixed四舍六入方法
2017/08/21 Javascript
angularJS实现动态添加,删除div方法
2018/02/27 Javascript
JavaScript数组、json对象、eval()函数用法实例分析
2019/02/21 Javascript
vue双向绑定及观察者模式详解
2019/03/19 Javascript
jquery实现自定义树形表格的方法【自定义树形结构table】
2019/07/12 jQuery
vue项目,代码提交至码云,iconfont的用法说明
2020/07/30 Javascript
vue 导航锚点_点击平滑滚动,导航栏对应变化详解
2020/08/10 Javascript
解决Vue-cli无法编译es6的问题
2020/10/30 Javascript
[08:44]和酒神一起战斗 DOTA2教你做大人
2014/03/27 DOTA
python3连接MySQL数据库实例详解
2018/05/24 Python
详解如何从TensorFlow的mnist数据集导出手写体数字图片
2019/08/05 Python
python @classmethod 的使用场合详解
2019/08/23 Python
pip 安装库比较慢的解决方法(国内镜像)
2019/10/06 Python
python自动化实现登录获取图片验证码功能
2019/11/20 Python
pygame库实现移动底座弹球小游戏
2020/04/14 Python
python GUI库图形界面开发之PyQt5控件QTableWidget详细使用方法与属性
2020/02/25 Python
Python Selenium自动化获取页面信息的方法
2020/08/31 Python
Python调用Redis的示例代码
2020/11/24 Python
css3翻牌翻数字的示例代码
2020/02/07 HTML / CSS
DOM和JQuery对象有什么区别
2016/11/11 面试题
《这儿真好》教学反思
2014/02/22 职场文书
幼儿园社区活动总结
2014/07/07 职场文书
人身损害赔偿协议书格式
2014/11/01 职场文书
《平移和旋转》教学反思
2016/02/19 职场文书