获取用户的真实ip

简介: 常见的坑有两个:   一、获取的是内网的ip地址。在nginx作为反向代理层的架构中,转发请求到php,java等应用容器上。结果php获取的是nginx代理服务器的ip,表现为一个内网的地址。php获取REMOTE_ADDR就是这样一个情况(内网地址)。

常见的坑有两个:

 

一、获取的是内网的ip地址。在nginx作为反向代理层的架构中,转发请求到php,java等应用容器上。结果php获取的是nginx代理服务器的ip,表现为一个内网的地址。php获取REMOTE_ADDR就是这样一个情况(内网地址)。

二、获取的是攻击者伪造的ip地址。攻击者可以随便伪造一个头部信息,随便填写一个ip放到头部发过来,php获取到HTTP_CLIENT_IP就是这样一个情况。伪造的ip,导致我们数据库存储是假的ip,无从真实去判断攻击者的来源。比如批量注册帐号的注册ip,登录的ip等。

     为避免伪造,不要使用discuz原来的获取ip函数,里面的判断优先级会使得攻击者容易伪造ip。

 

 

php代码:

 

 

 

function getIP() {

 

        if (getenv("HTTP_X_FORWARDED_FOR")) {

            //这个提到最前面,作为优先级,nginx代理会获取到用户真实ip,发在这个环境变量上,必须要nginx配置这个环境变量HTTP_X_FORWARDED_FOR

            $ip = getenv("HTTP_X_FORWARDED_FOR");

        } else if (getenv("REMOTE_ADDR")) {

           //在nginx作为反向代理的架构中,使用REMOTE_ADDR拿到的将会是反向代理的的ip,即拿到是nginx服务器的ip地址。往往表现是一个内网ip。

            $ip = getenv("REMOTE_ADDR");

        } else if ($_SERVER['REMOTE_ADDR']) {

            $ip = $_SERVER['REMOTE_ADDR'];

        } else if (getenv("HTTP_CLIENT_IP")) {

            //HTTP_CLIENT_IP攻击者可以伪造一个这样的头部信息,导致获取的是攻击者随意设置的ip地址。

            $ip = getenv("HTTP_CLIENT_IP");

        } else {

            $ip = "unknown";

        }

        return $ip;

    }

 

 

 

说明

 

在反向代理架构中,不能通过REMOTE_ADDR来获取用户的真实ip!

 

以前的理解方式有误(更新一下)

一般的方式是这样:

nginx>>(fastcgi方式)>>php引擎

nginx把REMOTE_ADDR传递给了php。代表的是当前与nginx通信的客户端ip,一般情况下(非反向代理),这个客户就是用户的浏览器,所以得到的用户的ip。


假设做了反向代理架构,是下面这样子的:


用 户>>>>>>>>>>>服务器 a>>>>>>>>>>>>>>>>>>nginx>>>>>>>>>>>>>> (fastcgi方式通信)>>>>>>>>>>>>php引擎


   用户访问一个域名,实际上是通过服务器a做了转发,转发到nginx去(反向代理架构经常会这样部署)


  于是,当前与nginx通信的客户端,就是服务器a的地址, REMOTE_ADDR就是a服务器的地址了。


  如何判断:nginx的上一层是不是还有一层。像上面的情况就还有一层。所以得到的将会是服务器a的地址。

 

 

 

总结:在nginx作为反向代理的架构中,php的REMOTE_ADDR(其他语言也是类似的名称)拿到的将会是nginx代理的ip地址。拿不到用户的真实ip,拿到是nginx反向代理服务器地址。

 

REMOTE_ADDR本意就是远程的地址,nginx是代理层,转发请求到php,php获取到的远程地址实际上是nginx反向代理服务器ip,这是符合协议规则的。

 

但是,可以让nginx帮助我们拿到用户的真实ip,写到一个环境变量中,然后转发给我们,只要按照某个约定的名称即可,比如约定名称为HTTP_X_FORWARD_FOR(也可以约定其他名称,关键看nginx中配置,可以全公司考虑统一)

 

 

nginx配置类似于这样:

 

fastcgi_param  HTTP_X_FORWARD_FOR  $remote_addr;

 

 上一句的目的是,将HTTP_X_FORWARD_FOR的值设置为$remote_addr的值。也就是将用户真实的ip(或用户使用代理的ip)放到HTTP_X_FORWARD_FOR中去。

 

 $remote_addr是nginx的内置变量,这个变量它得到是用户真实的ip地址(用户使用了代理,则就是代理的ip地址)。

 

于是在php端通过getenv("HTTP_X_FORWARDED_FOR")就可以获取到nginx传递过来的值,是用户真实的ip地址。

目录
相关文章
|
JSON easyexcel Java
EasyExcel的简单使用
EasyExcel的简单使用,以及如何通过postman进行导入导出功能的调试
1669 1
|
8月前
|
存储 机器学习/深度学习 应用服务中间件
阿里云服务器架构解析:从X86到高性能计算、异构计算等不同架构性能、适用场景及选择参考
当我们准备选购阿里云服务器时,阿里云提供了X86计算、ARM计算、GPU/FPGA/ASIC、弹性裸金属服务器以及高性能计算等多种架构,每种架构都有其独特的特点和适用场景。本文将详细解析这些架构的区别,探讨它们的主要特点和适用场景,并为用户提供选择云服务器架构的全面指南。
926 18
|
Java Linux 开发工具
用sdkman管理多个jdk切换
【10月更文挑战第13天】SDKMAN 是一个用于在基于 Unix 的系统(如 Linux 和 macOS)上管理多个软件开发工具包(SDK)版本的工具,特别适用于管理不同版本的 JDK。通过 SDKMAN,开发者可以轻松安装、切换和设置默认 JDK 版本,提高开发效率。安装后,可以通过 `sdk list java` 查看可用版本,使用 `sdk install java` 安装特定版本,并通过 `sdk use java` 切换版本。此外,还可以设置默认 JDK 版本,确保新终端会话中自动使用指定版本。验证版本切换是否成功,只需运行 `java -version` 命令即可。
1014 1
|
NoSQL Java 关系型数据库
【Redis系列笔记】分布式锁
分布式锁:满足分布式系统或集群模式下多进程可见并且互斥的锁。 分布式锁的核心思想就是让大家都使用同一把锁,只要大家使用的是同一把锁,那么我们就能锁住线程,不让线程进行,让程序串行执行,这就是分布式锁的核心思路
1399 2
|
Kubernetes 网络安全 网络架构
Docker不同宿主机网络打通
【8月更文挑战第20天】在不同宿主机上打通Docker网络可通过多种方法:1) 使用Docker原生的Overlay或Macvlan网络驱动实现跨主机通信,如Overlay网络利用VXLAN技术连接多台宿主机,Macvlan则让容器直接接入物理网络;2) 利用第三方工具如Weave Net或Flannel构建虚拟网络,Weave Net简化网络配置,Flannel则适用于Kubernetes环境并通过UDP封装数据包实现通信。实施前需确保宿主机间网络畅通且防火墙设置适当。
547 2
|
自然语言处理 监控 Cloud Native
探索微服务架构中的服务网格Service Mesh
【10月更文挑战第7天】服务网格(Service Mesh)是微服务架构中的关键组件,通过在每个服务实例旁部署Sidecar代理,实现服务间通信的管理、监控和安全增强。本文介绍了服务网格的基本概念、核心组件、优势及实施步骤,探讨了其在现代开发中的应用,并提供了实战技巧。
|
Java Linux Maven
用sdkman在linux上管理多个java版本
本文介绍了如何在Linux上使用SDKMAN来管理多个Java版本,包括安装SDKMAN、验证安装、列出和安装不同版本的JDK、Maven和Gradle,以及如何切换使用不同版本。
965 0
|
域名解析 缓存 网络协议
找不到DNS地址的解决方案
找不到DNS地址的解决方案
2290 1
|
网络协议 Linux 网络架构
【网络技术】什么是CIDR
【网络技术】什么是CIDR
1183 0
|
监控 定位技术 数据中心
住宅ip与数据中心ip代理的区别是什么
代理IP分为住宅IP和数据中心IP。住宅IP由ISP提供,更难被网站检测,适合需要高匿名度和广泛地理位置的业务,如广告发布和价格比较。数据中心IP源自服务器,虽速度快但易被识别,常用于数据抓取和SEO。住宅IP因其真实用户特性,较少被封锁,但成本较高。选择类型应基于具体使用场景,如小规模数据抓取可选数据中心IP。