项目中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 相关文章推荐
destoon在各个服务器下设置URL Rewrite(伪静态)的方法
Jun 21 Servers
Linux安装Nginx步骤详解
Mar 31 Servers
iSCSI服务器CHAP双向认证配置
Apr 01 Servers
Nginx动静分离配置实现与说明
Apr 07 Servers
openstack云计算keystone组件工作介绍
Apr 20 Servers
Vscode中SSH插件如何远程连接Linux
May 02 Servers
nginx 配置缓存
May 11 Servers
Win Server2016远程桌面如何允许多用户同时登录
Jun 10 Servers
TaiShan 200服务器安装Ubuntu 18.04的图文教程
Jun 28 Servers
nginx静态资源的服务器配置方法
Jul 07 Servers
详解apache编译安装httpd-2.4.54及三种风格的init程序特点和区别
Jul 15 Servers
在windows server 2012 r2中安装mysql的详细步骤
Jul 23 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生成便于打印的网页
2006/10/09 PHP
PHP魔术方法__GET、__SET使用实例
2014/11/25 PHP
Laravel中正确地返回HTTP状态码方法示例
2019/09/10 PHP
浅谈thinkphp的nginx配置,以及重写隐藏index.php入口文件方法
2019/10/12 PHP
laravel框架中间件简单使用方法示例
2020/01/25 PHP
利用location.hash实现跨域iframe自适应
2010/05/04 Javascript
关于javascript function对象那些迷惑分析
2011/10/24 Javascript
Jquery实现列表(隔行换色,全选,鼠标滑过当前行)效果实例
2013/06/09 Javascript
Jquery利用mouseenter和mouseleave实现鼠标经过弹出层且可以点击
2014/02/12 Javascript
Google官方支持的NodeJS访问API,提供后台登录授权
2014/07/29 NodeJs
jQuery遍历json中多个map的方法
2015/02/12 Javascript
深入理解JavaScript系列(38):设计模式之职责链模式详解
2015/03/04 Javascript
基于css3新属性transform及原生js实现鼠标拖动3d立方体旋转
2016/06/12 Javascript
vue.js动态数据绑定学习笔记
2017/05/19 Javascript
js中如何完美的解析数据
2018/03/18 Javascript
css配合JavaScript实现tab标签切换效果
2018/10/11 Javascript
JS跨域请求的问题解析
2018/12/03 Javascript
vue使用websocket的方法实例分析
2019/06/22 Javascript
详解JavaScript 事件流
2020/09/02 Javascript
[06:45]2018DOTA2亚洲邀请赛 4.5 SOLO赛 Sccc vs Maybe
2018/04/06 DOTA
Hadoop中的Python框架的使用指南
2015/04/22 Python
numpy中索引和切片详解
2017/12/15 Python
Python3中的bytes和str类型详解
2019/05/02 Python
Python实现html转换为pdf报告(生成pdf报告)功能示例
2019/05/04 Python
Python对接支付宝支付自实现功能
2019/10/10 Python
python实现AdaBoost算法的示例
2020/10/03 Python
详解Html5 Canvas画线有毛边解决方法
2018/03/01 HTML / CSS
html5定位并在百度地图上显示的示例
2014/04/27 HTML / CSS
印度尼西亚最完整和最大的在线药房网站:Farmaku.com
2019/11/23 全球购物
过滤器的用法
2013/10/08 面试题
2014年乡镇人大工作总结
2014/11/25 职场文书
职代会闭幕词
2015/01/28 职场文书
pytorch中的numel函数用法说明
2021/05/13 Python
方法汇总:Python 安装第三方库常用
2022/04/26 Python
Java Spring Lifecycle的使用
2022/05/06 Java/Android