多级代理下Nginx获取真实用户IP地址的总结

声明:本文参考http://www.ttlsa.com/nginx/nginx-get-user-real-ip/并做了一些补充讲解,希望会更加清晰明了~

随着nginx的迅速崛起,越来越多公司将apache更换成nginx. 同时也越来越多人使用nginx作为负载均衡, 并且代理前面可能还加上了CDN加速,但是随之也遇到一个问题:nginx如何获取用户的真实IP地址,如果后端是apache,请跳转到<apache获取用户真实IP地址>,如果是后端真实服务器是nginx,那么继续往下看。

实例环境:
用户IP 120.22.11.11
CDN前端 61.22.22.22
CDN中转 121.207.33.33
公司NGINX前端代理 192.168.50.121(外网121.207.231.22)

1、使用CDN自定义IP头来获取

假如说你的CDN厂商使用nginx,那么在nginx上将$remote_addr赋值给你指定的头,方法如下:

proxy_set_header remote-user-ip $remote_addr;

//如上,后端将会收到remote_user_ip的http头,有些人可能会挑错了,说我设置的头不是remote-user-ip吗,怎么写成了remote_user_ip,是不是作者写错了.请参考文章:<nginx反向代理proxy_set_header自定义header头无效>

后端PHP代码getRemoteUserIP.PHP

<?php
    $ip = getenv("HTTP_REMOTE_USER_IP");
    echo $ip;   
?>

访问getRemoteUserIP.php,结果如下:

120.22.11.11 //取到了真实的用户IP

注:这里$remote_addr是nginx的变量,一般情况是,是报文发送方的IP地址,如果发送方为proxy,那么这里就是proxy的ip,而非用户的真实ip.

注意:这里面会有一个问题,就是所谓的XFF欺骗,当用户直接访问后端的时候,并且他伪造了HTTP报头REMOTE_USER_IP,那么后端获取到的,将是一个虚假的用户IP,这个时候可能会产生一些安全问题。如果可以,建议的做法是:后端服务不允许对外部用户访问,最前端的代理,proxy_set_header xxxxx $remote_addr;这样就能解决欺骗,因为$remote_addr获取的是用户IP数据包中的IP,而非伪造的HTTP报文首部。

2、通过HTTP_X_FORWARDED_FOR获取IP地址

一般情况下CDN服务器都会传送HTTP_X_FORWARDED_FOR头。而且会用proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

这里,$proxy_add_x_forwarded_for是一个神奇的变量,假如接收到的报文已经含有X-FORWARDED-FOR首部,那么nginx将在后面添加上$remote_addr(也就是发送者的ip地址在最后),因此后端的真实服务器获取HTTP_X_FORWARDED_FOR头,截取字符串第一个不为unkown的IP作为用户真实IP地址, 例如:

120.22.11.11,  61.22.22.22,  121.207.33.33,192.  168.50.121(用户IP,CDN前端IP,CDN中转,公司NGINX代理)

getFor.php

<?php
    $ip = getenv("HTTP_X_FORWARDED_FOR");
    echo $ip;
?>

访问getFor.php结果如下:

120.22.11.11,61.22.22.22,121.207.33.33,192.168.50.121

如果你是php程序员,你获取第一个不为unknow的ip地址,这边就是120.22.11.11.

同理,为防止XFF欺骗,除了第一层代理,后面的多禁止普通用户访问,第一层代理,用$remote_addr来设置pass X-Forwarded-For即可。

3.使用nginx自带模块realip获取用户IP地址

有些时候,中间或者后端的代理,都要能够被普通用户访问,也或者在nginx日志中,想让$remote_adrr配置的格式,能显示外界用户的ip,这个时候,就要使用realip模块了。
安装nginx之时加上realip模块,我的参数如下:

./configure --prefix=/usr/local/nginx-1.4.1 --with-http_realip_module

真实服务器nginx配置

server {
    listen       80;
    server_name  www.ttlsa.com;
    access_log  /data/logs/nginx/www.ttlsa.com.access.log  main;
 
    index index.php index.html index.html;
    root /data/site/www.ttlsa.com;
 
    location /
    {
            root /data/site/www.ttlsa.com;
    }
    location = /getRealip.php
    {
            set_real_ip_from  192.168.50.0/24;
            set_real_ip_from  61.22.22.22;
            set_real_ip_from  121.207.33.33;
            set_real_ip_from 127.0.0.1;
            real_ip_header    X-Forwarded-For;
            real_ip_recursive on;
            fastcgi_pass  unix:/var/run/phpfpm.sock;
            fastcgi_index index.php;
            include fastcgi.conf;
    }
}

getRealip.php内容

<?php
    $ip =  $_SERVER['REMOTE_ADDR'];
    echo $ip;   
?>

访问www.ttlsa.com/getRealip.php,返回:

120.22.11.11

如果注释 real_ip_recursive on或者 real_ip_recursive off
访问www.ttlsa.com/getRealip.php,返回:

121.207.33.33

很不幸,获取到了中继的IP,real_ip_recursive的效果看明白了吧.

set_real_ip_from:真实服务器上一级代理的IP地址或者IP段,可以写多行
real_ip_header:从哪个header头检索出要的IP地址
real_ip_recursive:递归排除IP地址,ip串从右到左开始排除set_real_ip_from里面出现的IP,如果出现了未出现这些ip段的IP,那么这个IP将被认为是用户的IP。例如我这边的例子,真实服务器获取到的IP地址串如下:
120.22.11.11,61.22.22.22,121.207.33.33,192.168.50.121
在real_ip_recursive on的情况下
61.22.22.22,121.207.33.33,192.168.50.121都出现在set_real_ip_from中,仅仅120.22.11.11没出现,那么他就被认为是用户的ip地址,并且赋值到remote_addr变量

在real_ip_recursive off或者不设置的情况下
192.168.50.121出现在set_real_ip_from中,排除掉,接下来的ip地址便认为是用户的ip地址

如果仅仅如下配置:

set_real_ip_from   192.168.50.0/24;
set_real_ip_from 127.0.0.1;
real_ip_header    X-Forwarded-For;
real_ip_recursive on;

访问结果如下:

121.207.33.33

这里可能有朋友会不理解,我来补充解释一下http_realip_module这个模块好了,它包括三个指令:

1、set_real_ip_from 是指接受从哪个信任前代理处获得真实用户ip

2、real_ip_header 是指从接收到报文的哪个http首部去获取前代理传送的用户ip

3、real_ip_recursive 是否递归地排除直至得到用户ip(默认为off)

首先,real_ip_header 指定一个http首部名称,默认是X-Real-Ip,假设用默认值的话,nginx在接收到报文后,会查看http首部X-Real-Ip。

(1)如果有1个IP,它会去核对,发送方的ip是否在set_real_ip_from指定的信任ip列表中。如果是被信任的,它会去认为这个X-Real-Ip中的IP值是前代理告诉自己的,用户的真实IP值,于是,它会将该值赋值给自身的$remote_addr变量;如果不被信任,那么将不作处理,那么$remote_addr还是发送方的ip地址。

(2)如果X-Real-Ip有多个IP值,比如前一方代理是这么设置的:proxy_set_header X-Real-Ip $proxy_add_x_forwarded_for;

得到的是一串IP,那么此时real_ip_recursive 的值就至关重要了。nginx将会从ip列表的右到左,去比较set_real_ip_from 的信任列表中的ip。如果real_ip_recursive为off,那么,当最右边一个IP,发现是信任IP,即认为下一个IP(右边第二个)就是用户的真正IP;如果real_ip_recursive为on,那么将从右到左依次比较,知道找到一个不是信任IP为止。然后同样把IP值复制给$remote_addr。(可以参考上面的例子,帮助理解这个过程)

因此,明白了整个过程后,我们知道,用realip模块是非常好用的,能满足各种获取用户IP的需求,而且不会受到XFF欺骗!

那么问题来了,后端除了想获取用户ip,也想获取代理ip,怎么办呢?那么此时$proxy_add_x_forwarded_for派上用场。只需要在每一层代理IP,都保持一个良好的习惯:proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;然后后端得到的X-Forwarded-For首部,依次就是用户IP到各层代理的IP,至于最靠近自己的代理ip,各种web开发语言都有获取发送方真实IP的接口了,然后你知道该怎么做了吧?!

Nginx获取真实用户IP相关推荐

  1. nginx经过多层代理后获取真实来源ip

    nginx取 $remote_addr 当做真实ip,而事实上,$http_X_Forwarded_For 才是用户真实ip,$remote_addr只是代理上一层的地址 解决方案: 在 http 模 ...

  2. Nginx在多层代理下获取真实客户端IP地址

    最近在研究nginx中如何获取真实客户端IP的方法.众所周知,在编译Nginx时,可通过添加http_realip_module模块来获取真实客户端IP地址.何为真实IP地址呢?请看下图,既获取到的真 ...

  3. nodejs+nginx获取真实ip

    nodejs + nginx获取真实ip分为两部分: 第一.配置nginx: 第二.通过nodejs代码获取: 其他语言也是一样的,都是配置nginx之后,在http头里面获取"x-forw ...

  4. 学习笔记 - Nginx在多层代理下获取真实客户端IP地址

    最近在研究nginx中如何获取真实客户端IP的方法.众所周知,在编译Nginx时,可通过添加http_realip_module模块来获取真实客户端IP地址.何为真实IP地址呢?请看下图,既获取到的真 ...

  5. Java获取登录用户IP地址

    Java获取登录用户IP地址 /*** @param * @return * @throws * @description * @author wqd* @date 2021/9/21 13:45*/ ...

  6. nginx 获取真实ip

    问题背景: 在实际应用中,我们可能需要获取用户的ip地址,比如做异地登陆的判断,或者统计ip访问次数等,通常情况下我们使用request.getRemoteAddr()就可以获取到客户端ip,但是当我 ...

  7. nginx curl命令有效 curl_setopt无效_日志分析系列(外传一):Nginx透过代理获取真实客户端IP...

    本系列中的故事纯属虚构,如有雷同实属巧合 小B是Q公司的安全攻城狮,为了完成任务小B开始做起了调研(欲知背景如何,且听下回分说). 首先小B弄明白了Q公司的应用系统架构是:Client --> ...

  8. Nginx透过代理获取真实客户端IP

    本系列中的故事纯属虚构,如有雷同实属巧合 小B是'柒'公司的安全攻城狮,为了完成任务小B开始做起了调研(欲知背景如何,且听下回分说). 首先小B弄明白了'柒'公司的应用系统架构是:Client --& ...

  9. 使用nginx代理,怎么获取真实的IP

    1.在nginx.conf配置中加入配置信息 proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; pr ...

最新文章

  1. qq浏览器主页_QQ浏览器遭恶意病毒篡改主页,无法更改的解决办法
  2. 电脑的发展史_互联网发展史 硅谷传奇之苹果公司
  3. 深入理解JVM虚拟机(七):虚拟机字节码执行引擎
  4. 智慧显示:5G时代的新机遇
  5. window.open打开页面并传值,window. location.search遍历获取到的请求链接中的所有参数
  6. Web API的CORS
  7. java取拼音首字母_java取出汉字字符串的拼音首字母
  8. 为开发者们准备的10款超棒的jQuery视频插件
  9. 3Ds MAX 软件介绍
  10. 如何将多张图片转换为pdf格式
  11. uniapp 连接ibeacon beacon
  12. iOS 字体转换
  13. Vue3中TSX和h函数的用法
  14. 写出HTML的基本结构 做简要说明,北京市顺义区2017年--2018年届高三二模语文试题(卷)与答案解析.doc...
  15. Android 多进程同时打开相机
  16. cf 940E Cashback
  17. 《论语》原文及其全文翻译 学而篇12
  18. tushare +talib 三指标筛选股票
  19. Kaggle系列(3)- Telco Customer Churn
  20. php mysql 上一页 下一页 分页代码片段

热门文章

  1. IoC容器和 Dependency Injection模式 Inversion of Control Containers and the Dependency Injection pattern
  2. 基于NLM的插值算法
  3. 计算机软件技术介绍ppt,计算机软件技术基础.ppt
  4. matlab 变分不等式,求解变分不等式的matlab程序
  5. Unity使用反射探头实现地面的镜面反射
  6. 二年级数学计算机教学教案,人教版-小学二年级数学上册全套教案.pdf
  7. 成功将 戴尔灵越燃7000 II 改装Win7
  8. lua中的整除与取整数
  9. 技术胖Web前端视频教程合集
  10. 应用及实例,在信用卡业务中的数据挖掘技术分析