Skip to content

andychu46/nginx_realip_plus

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

在nginx前有CDN时获取用户真实IP

介绍

通常在源机前有反代时我们使用nginx的realip模块来获取客户的IP; realip支持多个set_real_ip_from,但只支持一个real_ip_header; 但当在复杂网络环境,有多个不同的反代时,realip就不够用了; 比如在我的项目历史变迁中,源机对外有双线公网IP,内部有2个内网网段,有百度和阿里的CDN/WAF; 百度使用http_x_forwarded_for来传递真实ip,阿里使用自定的header头传递;

优势

  • 支持http_x_forwarded_for取IP
  • 支持自定义header取IP
  • 支持阿里云、百度云加速等cdn或waf获取IP
  • 支持IPV6地址
  • 支持IP黑白名单

项目地址

背景知识

nginx中的几个变量: remote_addr 代表客户端的IP,但它的值是你服务器网卡接入端发送方的值. X-Forwarded-For(简称XFF), 是一个 HTTP 扩展头部。它最开始是由 Squid 这个缓存代理软件引入,用来表示 HTTP 请求端真实 IP。 XFF 的内容由「英文逗号 + 空格」隔开的多个部分组成,最开始的是离服务端最远的设备 IP,然后是每一级代理设备的 IP。(注意:如果未经严格处理,可以被伪造) 如果一个 HTTP 请求到达服务器之前,经过了三个代理 Proxy1、Proxy2、Proxy3,那么按照 XFF 标准,服务端最终会收到以下信息

X-Forwarded-For: clientip, proxy1ip, proxy2ip

这里没有proxy3ip,proxy3ip为当前接入端的remote_addr。

比如 PHP 可以直接使用

$_SERVER['REMOTE_ADDR']

获取到proxy3ip,也可以获取到X_FORWARDED_FOR

$_SERVER['HTTP_X_FORWARDED_FOR']

但HTTP_X_FORWARDED_FOR是可以伪造的,我们伪造一个‘112.1.1.1’发给ip所在地网站进行测试。

curl -s https://api.vore.top/api/IPdata?ip= -H 'X-Forwarded-For: 112.1.1.1,222.1.1.1'
{
    "code": 200,
    "msg": "SUCCESS",
    "ipinfo": {
        "type": "ipv4",
        "text": "112.1.1.1",
        "cnip": true
    },
    "ipdata": {
        "info1": "江苏省",
        "info2": "淮安市",
        "info3": "",
        "isp": "移动"
    },
    "adcode": {
        "o": "江苏省淮安市 - 移动",
        "p": "江苏",
        "c": "淮安",
        "n": "江苏-淮安",
        "r": "江苏-淮安",
        "a": "320800",
        "i": true
    },
    "tips": "接口由VORE-API(https:\/\/api.vore.top\/)免费提供",
    "time": 1725340014
}

它原样输出了我们伪造的XFF。 如果你想使用HTTP_X_FORWARDED_FOR取客户ip,那么你需要确定remote_addr的IP是认可的proxy地址。

解决问题

百度cdn通过HTTP_X_FORWARDED_FOR传输真实ip

安装部署

各文件放置在nginx.conf所在目录,通常是/opt/nginx/conf/

百度cdnip地址文件,如果没有使用百度云,请设为空。

geo.cdn_ip.conf geo.cdn_proxy.conf

ip白名单文件,如果开启访问限制,请写入白名单IP

geo.allow.conf;

127.0.0.1/32 1; #host
192.168.0.0/24 1; #lan1

ip黑名单,禁止访问的IP

geo.abuse.conf

117.149.203.13 1;

realip文件

ngxipcofig.conf

反代nginx主体文件

nginx.conf

http 
{

    # 其他配置 ...

    #如果header头有下划线,需打开nderscores_in_headers
    #underscores_in_headers on;
    #ignore_invalid_headers off;
    #请改成你认可的合法proxyip
    set_real_ip_from   192.168.250.158/31;
    # 使用"c1g-clientip"头获取真实IP,需要同步修改ngxinpconfig.conf中配制默认为“X-Real-IP”
    real_ip_header    c1g-clientip;
    # 可选:如果有多个代理,可以使用此指令指定“X-Forwarded-For”中应该使用哪个IP地址
    # real_ip_recursive on;


    #载入realip
    include ngxipcofig.conf;

    #日志文件$clientRealIp 为真实客户ip
    log_format  access  '$clientRealIp - $remote_user [$time_local] "$request" '
               '$status $body_bytes_sent "$http_referer" '
               '"$http_user_agent" $http_x_forwarded_for';

    upstream www_server {
        server   192.168.0.80:80;
    }
    # 测试主机 http://localhost/showip
    server
    {
        listen       80;
        server_name  localhost;

        location /showip {
                default_type text/plain; 
                echo show realip infomation;
                echo_duplicate 20 "---";
                echo;
                echo time_local\t\t\t\t: $time_local;
                echo 原始ip(remote_addr)\t\t\t: $remote_addr;
                echo realip(realip_remote_addr)\t\t: $realip_remote_addr;
                echo 原始端口(REMOTE_PORT)\t\t\t: $remote_port;
                echo realip端口(realip_REMOTE_PORT)\t\t: $realip_remote_port;
                echo 下发真实ip及端口(proxyrealip)\t\t: $proxyrealip;
                echo forwarded原始(http_x_forwarded_for)\t: $http_x_forwarded_for;
                echo forwarded增加ip(proxypass_forwarded_for): $proxypass_forwarded_for;
                echo forwarded中第一个(ForwardedFirstIp)\t: $forwardedfirstip;
                echo forwarded中最后一个(ForwardedLastIp)\t: $forwardedlastip;
                echo ip来源首次标记(clientipfrom)\t\t: $clientipfrom;
                echo ip来源二次标记(clientipfrominner)\t: $clientipfrominner;               
                echo 客户真实ip(clientRealIpTmp)\t\t: $clientRealIpTmp;                
                echo 最终真实ip(clientRealIp)\t\t: $clientRealIp;
                echo 是否通过负载均衡(is_F5_ip)\t\t: $is_f5_ip;
                echo 是否来自cdn(clientipfromf5iscdn)\t: $clientipfromf5iscdn;
                echo ip来源最终标记(clientipselector)\t: $clientipselector;
                echo 白名单ip(is_white_ip)\t\t\t: $white_ip;
                echo F5最后ip(F5LastIp)\t\t\t: $f5LastIp;
                echo x_real_ip原始(http_x_real_ip)\t\t: $http_x_real_ip;
                echo x_real_ip中取出realip(httpxrealip)\t: $httpxrealip;
                echo 自定义header头(http_c1g_clientip)\t: $http_c1g_clientip;
        }

        #向上游传递真实ip
        location /
        {
            proxy_set_header Host  $host;
            proxy_set_header X-Real-IP $proxyrealip;
            proxy_set_header X-Client-IP $proxycheckip;
            proxy_set_header X-Client-Selector $clientipselector;
            proxy_set_header X-Forwarded-For $proxypass_forwarded_for;
            proxy_pass http://www_server;
        }

    }

}

上游nginx主体文件

nginx.conf

http 
{
    # 其他配置 ...

    # 内网ip
    set_real_ip_from 192.168.0.0/24;
    real_ip_header X-Real-IP;

    #载入ip配置
    include ngxipcofig.conf;
}

重启nginx

/opt/nginx/sbin/nginx -t /opt/nginx/sbin/nginx -s reload

访问测试页面

http://localhost/showip

或者使用命令测试 curl -s http://192.168.244.8/showip -H 'Host:localhost' -H 'X-Forwarded-For: 223.5.5.3,223.5.5.2' -H 'c1g-clientip: 211.1.1.1'

show realip infomation
------------------------------------------------------------
time_local				: 03/Sep/2024:17:56:12 +0800
原始ip(remote_addr)			: 211.1.1.1
realip(realip_remote_addr)		: 192.168.244.2
原始端口(REMOTE_PORT)			: 
realip端口(realip_REMOTE_PORT)		: 52922
下发真实ip及端口(proxyrealip)		: 211.1.1.1:
forwarded原始(http_x_forwarded_for)	: 223.5.5.3,223.5.5.2
forwarded增加ip(proxypass_forwarded_for): 223.5.5.3,223.5.5.2, 211.1.1.1
forwarded中第一个(ForwardedFirstIp)	: 223.5.5.3
forwarded中最后一个(ForwardedLastIp)	: 223.5.5.2
ip来源首次标记(clientipfrom)		: 0
ip来源二次标记(clientipfrominner)	: 
客户真实ip(clientRealIpTmp)		: 211.1.1.1
最终真实ip(clientRealIp)		: 211.1.1.1
是否通过负载均衡(is_F5_ip)		: 0
是否来自cdn(clientipfromf5iscdn)	: 0
ip来源最终标记(clientipselector)	: 0
白名单ip(is_white_ip)			: 0
F5最后ip(F5LastIp)			: 211.1.1.1
x_real_ip原始(http_x_real_ip)		: 
x_real_ip中取出realip(httpxrealip)	: 211.1.1.1
自定义header头(http_c1g_clientip)	: 211.1.1.1

About

nginx realip plus 获取用户真实ip

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published