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

页面上显示目前我目前的 IP49.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/

原文地址:https://www.cnblogs.com/lovebing/p/6823826.html