后端nginx使用set_real_ip_from获取用户真实IP

随着nginx的迅速崛起,越来越多公司将apache更换成nginx. 同时也越来越多人使用nginx作为负载均衡, 并且代理前面可能还加上了CDN加速,但是随之也遇到一个问题:nginx如何获取用户的真实IP地址.

前言:Nginx ngx_http_realip_module

官方说明:

Module ngx_http_realip_module

例子1

realip模块的作用是:当本机的nginx处于一个反向代理的后端时获取到真实的用户IP

如果没有realip模块,nginx的access_log里记录的IP会是反向代理服务器的IP,PHP中$_SERVER['REMOTE_ADDR']的值也是反向代理的IP。

而安装了realip模块,并且配置正确,就可以让nginx日志和php的REMOTE_ADDR都变成真实的用户IP。

举一个最简单的例子,网络架构如图:

如果不做任何配置,后端web服务器nginx日志里记录的IP将会是10.10.10.10,这个时候我们增加如下nginx配置:

set_real_ip_from 10.10.10.10;

real_ip_header X-Forwarded-For;

  • set_real_ip_from指令是告诉nginx,10.10.10.10是我们的反代服务器(信任服务器,记住这个名词,下面会提到),不是真实的用户IP,
  • real_ip_header则是告诉nginx真正的用户IP是存在X-Forwarded-For请求头中(对X-Forwarded-For不了解的同学请自行百度)。

重新加载nginx配置之后,就可以看到nginx日志里记录的IP就是123.123.123.123了,php里的REMOTE_ADDR也是123.123.123.123。

realip模块还提供了另外一个指令real_ip_recursive,可以用来处理更加复杂的情况,架构如图:

这个时候如果还用上面的配置,后端nginx的日志里显示的IP就变成了192.168.1.10了,这个时候就需要real_ip_recursive这个指令了。

set_real_ip_from 10.10.10.10;

set_real_ip_from 192.168.1.10;

real_ip_header X-Forwarded-For;

real_ip_recursive on;

官网文档对于real_ip_recursive指令的解释十分拗口,看了老半天才明白。

首先要明确一点,realip模块生效的前提是:直接连接nginx的ip是在set_real_ip_from中指定的。

  • 当real_ip_recursive为off时,nginx会把real_ip_header指定的HTTP头中的最后一个IP当成真实IP
  • 当real_ip_recursive为on时,nginx会把real_ip_header指定的HTTP头中的最后一个不是信任服务器的IP当成真实IP

在这个例子中,当请求到达后端web服务器时,X-Forwarded-For应该是123.123.123.123, 192.168.1.10。

如果real_ip_recursive为off,nginx取X-Forwarded-For的最后一个IP也就是192.168.1.10作为真实IP。

如果real_ip_recursive为on,由于192.168.1.10是信任服务器IP,所以nginx会继续往前查找,发现123.123.123.123不是信任服务器IP,就认为是真实IP了。

例子2:

实例环境:

  • 用户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;

后端PHP代码getRemoteUserIP.php

复制代码
<?php
$ip = getenv("HTTP_REMOTE_USER_IP"); 
echo $ip;
?>

访问getRemoteUserIP.php,结果如下:

复制代码
120.22.11.11 //取到了真实的用户IP,如果CDN能给定义这个头的话,那这个方法最佳

2、通过HTTP_X_FORWARDED_FOR获取IP地址

一般情况下CDN服务器都会传送HTTP_X_FORWARDED_FOR头,这是一个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.

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

安装nginx之时加上realip模块,我的参数如下:

复制代码
./configure --prefix=/usr/local/nginx-1.4.1 --with-http_realip_module

真实服务器nginx配置

复制代码
server {
    listen 80;
    server_name www.zcy.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

4、三种在CDN环境下获取用户IP方法总结

4.1 CDN自定义header头

  • 优点:获取到最真实的用户IP地址,用户绝对不可能伪装IP
  • 缺点:需要CDN厂商提供

4.2 获取forwarded-for头

  • 优点:可以获取到用户的IP地址
  • 缺点:程序需要改动,以及用户IP有可能是伪装的

4.3 使用realip获取

  • 优点:程序不需要改动,直接使用remote_addr即可获取IP地址
  • 缺点:ip地址有可能被伪装,而且需要知道所有CDN节点的ip地址或者ip段

参考

后端nginx使用set_real_ip_from获取用户真实IP-CSDN博客

nginx之ngx_http_realip_module使用详解-腾讯云开发者社区-腾讯云

相关推荐
Arya_aa1 小时前
四:部署前端和后端
nginx
Java面试题总结2 小时前
一文搞定 Linux Nginx 从安装、启动到 nginx.conf 全配置详解(新手也能看懂)
linux·运维·nginx
MiNG MENS16 小时前
nginx 代理 redis
运维·redis·nginx
珊瑚怪人17 小时前
一个域名问题
nginx
dxdz20 小时前
一文搞定 Linux Nginx 从安装、启动到 nginx.conf 全配置详解(新手也能看懂)
nginx
遇见火星20 小时前
Nginx 负载均衡配置模板:轮询、权重、IP哈希、最少连接
tcp/ip·nginx·负载均衡
untE EADO1 天前
Nginx代理到https地址忽略证书验证配置
运维·nginx·https
Treh UNFO1 天前
nginx的重定向
大数据·数据库·nginx
理人综艺好会1 天前
nginx了解
运维·nginx
likeGhee1 天前
docker创建nginx+keepalived+nacos集群(仅测试环境)
nginx·docker