PHP安全:如何正确的取得使用者 IP?
PHP安全:如何正确的取得使用者 IP?

很多网站都会有侦测用户 IP 的功能,不管是判断使用者来自哪边,或者是记录用户的位置。但是你知道吗?网络上大多数的教学全部都是「错误」的。正确的程序写法可以确保知道访客的 IP,但是错误的写法却可能让网站管理者永远不知道犯罪者的来源。
这次我们单就侦测 IP 的议题来探讨各种错误的写法。
你知道网络上的教学是不安全的吗?
我们先来看一下网络上的教学,让我们 Google 找一下「PHP 取得 IP」,就可以看到许多人热心的教学,我们随意挑一个常见的教学来看看。
以 PHP 为例:
<?php
if(!empty($_SERVER['HTTP_CLIENT_IP'])){
$myip
=
$_SERVER['HTTP_CLIENT_IP'];
}else
if(!empty($_SERVER['HTTP_X_FORWARDED_FOR'])){
$myip
=
$_SERVER['HTTP_X_FORWARDED_FOR'];
}else{
$myip=
$_SERVER['REMOTE_ADDR'];
}
echo
$myip;
?>
以 ASP.NET 为例:
Dim ClientIP As String = Request.ServerVariables("HTTP_X_FORWARDED_FOR")
IF ClientIP = String.Empty Then
ClientIP = Request.ServerVariables("REMOTE_ADDR")
End IF
这是一个很基本的写法、很正确的想法,如果 HTTP Header 中包含「Client-IP」,就先以他当作真实 IP。若包含「X-Forwarded-For」,则取他当作真实 IP。若两者都没有,则取「REMOTE_ADDR」变量作为真实 IP。因为当用户联机时透过代理服务器时,REMOTE_ADDR 会显示为代理服务器 Proxy 的 IP。部分代理服务器会将用户的原始真实 IP 放在 Client-IP 或 X-Forwarded-For header 中传递,如果在变量中呼叫则可以取得真实 IP。
但是你知道吗?网络上 80% 的教学写法全部都是「错误」的。
为什么这样说呢?请大家记得一件事情:「任何从客户端取得的资料都是不可信任的!」
窜改 HTTP Header
「X-Forwarded-For」这个变量虽然「有机会」取得使用者的真实 IP,但是由于这个值是从客户端传送过来的,所以「有可能」被使用者窜改。
举例来说,我写了一个小程序,侦测这些常见的 HTTP Header 判断 IP。并且使用 Burp Suite 这个工具来修改 HTTP Request。

页面上显示目前我目前的 IP「49.50.68.17」,并且其他的 header 是空的。但如果我今天使用 Burp Suite 之类的 Proxy 工具自行窜改封包,加上 X-Forwarded-For 或是 Client-IP header:



修改完毕之后,再到原本的显示 IP 接口,会发现网页错将我窜改的 header 当作正确的数据填入。

使用代理服务器 Proxy 的情况
使用代理服务器的情况下,HTTP Header 会有不同的行为。例如 Elite Proxy 如何隐藏客户端的真实 IP。以下简单介绍几种常见的状况给各位参考。
直接联机
(没有使用 Proxy)
- REMOTE_ADDR: 客户端真实 IP
- HTTP_VIA: 无
- HTTP_X_FORWARDED_FOR: 无
Transparent Proxy
- REMOTE_ADDR: 最后一个代理服务器 IP
- HTTP_VIA: 代理服务器 IP
- HTTP_X_FORWARDED_FOR: 客户端真实 IP,后以逗点串接多个经过的代理服务器 IP
Anonymous Proxy
- REMOTE_ADDR: 最后一个代理服务器 IP
- HTTP_VIA: 代理服务器 IP
- HTTP_X_FORWARDED_FOR: 代理服务器 IP,后以逗点串接多个经过的代理服务器 IP
High Anonymity Proxy (Elite Proxy)
- REMOTE_ADDR: 代理服务器 IP
- HTTP_VIA: 无
- HTTP_X_FORWARDED_FOR: 无 (或以逗点串接多个经过的代理服务器 IP)
实际情况
在我们测试的过程中,通常我们都会让浏览器自带 X-Forwarded-For,并且自行填入 IP。常常会发现有一些网站出现如下的警告…

有没有搞错?「上次登入位置 127.0.0.1」?没错,这个是知名论坛套件「Discuz!」的功能,抓取 IP 的功能也是不安全的写法。也有这样的经验,之前开着 X-Forwarded-For 的 header 到一些网站,竟然直接出现管理者后台!
你觉得只有一般人撰写的程序会有这样的问题吗?其实大型网站也可能会有类似的问题:

先不论为什么 127.0.0.1 会在美国,这样的写法可能会让管理者永远抓不到犯罪者的真实 IP,甚至攻击者可以窜改 header 插入特殊字符,对网站进行 SQL Injection 或者 Cross-Site Scripting 攻击。
正确又安全的方式
「任何从客户端取得的资料都是不可信任的!」
请各位开发者、管理者记住这个大原则,虽然这些 Request Header 可能含有真实 IP 的信息,但是因为他的安全性不高,因此我们绝对不能完全信赖这个数值。
那我们该怎么处理呢?我的建议是记录所有相关的 header 字段存入数据库,包含「REMOTE_ADDR」「X-Forwarded-For」等等,真正有犯罪事件发生时,就可以调出所有完整的 IP 信息进行人工判断,找出真正的 IP。当然从 header 存入的数值也可能会遭到攻击者窜改插入特殊字符尝试 SQL Injection,因此存入值必须先经过过滤,或者使用 Prepared Statement 进行存放。
可以参考的 HTTP Header(依照可能存放真实 IP 的顺序)
- HTTP_CLIENT_IP
- HTTP_X_FORWARDED_FOR
- HTTP_X_FORWARDED
- HTTP_X_CLUSTER_CLIENT_IP
- HTTP_FORWARDED_FOR
- HTTP_FORWARDED
- REMOTE_ADDR (真实 IP 或是 Proxy IP)
- HTTP_VIA (参考经过的 Proxy)
「黑客思维」就是找出网站任何可能窜改的弱点,从网页上的元素到 HTTP Header 都是尝试的对象。因此身为防御者一定要清楚的知道哪些数值是不能信赖的,不要再参考网络上错误的教学了!
来源:http://devco.re/blog/2014/06/19/client-ip-detection/
PHP安全:如何正确的取得使用者 IP?的更多相关文章
- 【翻译自mos文章】怎么正确的计算一个ip地址的subnet id?
怎么正确的计算一个ip地址的subnet id? 来源于: How to calculate the correct subnet for an interface (文档 ID 1059759.1) ...
- VM中ubuntu已经正确配置了静态IP仍无法上网
情况描述:正确配置了ubuntu的IP,getway,DNS..无法ping通getway. 环境:宿主机:win7 32Bit 虚拟机:ununtu 10.04 VM:9.0.1 build-8 ...
- 微信支付报ip错,怀疑是因为不能正确获取$_Server[addr])ip导致的
报如下错误,应该是本地测试环境不能正确获取客户ip导致的错误 果然 放到服务器上在测试就好了
- nginx反向代理下thinkphp、php获取不到正确的外网ip
在记录用户发送短信需要获取用户ip时,tp一直获取的是内网ip:10.10.10.10 tp框架获取ip方法:get_client_ip /** * 获取客户端IP地址 * @param intege ...
- Java正确获取客户端真实IP方法整理
在JSP里,获取客户端的IP地址的方法是:request.getRemoteAddr(),这种方法在大部分情况下都是有效的.但是在通过了Apache,Squid等反向代理软件就不能获取到客户端的真实I ...
- 干货:Java正确获取客户端真实IP方法整理
在JSP里,获取客户端的IP地址的方法是:request.getRemoteAddr(),这种方法在大部分情况下都是有效的.但是在通过了Apache,Squid等反向代理软件就不能获取到客户端的真实I ...
- C# 验证IP是否正确简易方法 源代码
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...
- Asp.Net Core2.0获取客户IP地址,及解决发布到Ubuntu服务器获取不到正确IP解决办法
1.获取客户端IP地址实现方法(扩展类) using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.ModelBinding; u ...
- TCP/IP 和 Socket 的关系
要写网络程序就必须用Socket,这是程序员都知道的.而且,面试的时候,我们也会问对方会不会Socket编程?一般来说,很多人都会说,Socket编程基本就是listen,accept以及send,w ...
随机推荐
- Python开发基础-Day16import模块导入和包的调用
模块概念 在Python中,一个.py文件就称之为一个模块(Module).使用模块组织代码,最大的好处是大大提高了代码的可维护性 模块一共三种:python标准库.第三方模块.应用程序自定义模块. ...
- 【BZOJ 1150】 1150: [CTSC2007]数据备份Backup (贪心+优先队列+双向链表)
1150: [CTSC2007]数据备份Backup Description 你在一家 IT 公司为大型写字楼或办公楼(offices)的计算机数据做备份.然而数据备份的工作是枯燥乏味 的,因此你想设 ...
- 【DFS】【贪心】Codeforces Round #411 (Div. 1) C. Ice cream coloring
对那个树进行dfs,在动态维护那个当前的冰激凌集合的时候,显然某种冰激凌仅会进出集合各一次(因为在树上形成连通块). 于是显然可以对当前的冰激凌集合贪心染色.暴力去维护即可.具体实现看代码.map不必 ...
- 20162303实验二 Java面向对象程序设计实验报告
北京电子科技学院(BESTI) 实 验 报 告 课程:程序设计与数据结构 班级: 1623 姓名: 石亚鑫 学号:20162303 成绩: 2分 指导教师:娄家鹏 王志强 实验日期:4月14日 实验密 ...
- Learning Spatial Regularization with Image-level Supervisions for Multi-label Image Classification
- 转载:通过扩大IE使用内存,解决skyline在IE下模型不能加载的方法
转自:https://www.cnblogs.com/cannel/p/5261009.html 环境:skyline TerraExploere 6.6,win 10 sp1 64位,ie 11 情 ...
- [转]SSIS Recordset Destination
本文转自:http://www.sqlis.com/sqlis/post/Shredding-a-Recordset.aspx Doing what to a recordset? Shredding ...
- RawCap抓取本地回环接口数据包
RawCap.exe --help ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 D: ...
- CSS权重的等级划分
CSS权重 CSS权重指的是样式的优先级,有两条或多条样式作用于一个元素,权重高的那条样式对元素起作用,权重相同的,后写的样式会覆盖前面写的样式. 权重的等级 可以把样式的应用方式分为几个等级,按照等 ...
- 批处理命令中set定义的两种变量介绍 计算机基础知识
摘自: http://www.amhl.net/wenzhang/DianNaoChangShi/20101201/127422.html 所谓的自定义变量,就是由我们来给它赋予值的变量. ①赋值变量 ...