PHP正確獲取客戶端IP地址


現狀

目前主流的函數方法:

<?php
function getIp() { if ($_SERVER["HTTP_CLIENT_IP"] && strcasecmp($_SERVER["HTTP_CLIENT_IP"], "unknown")) { $ip = $_SERVER["HTTP_CLIENT_IP"]; } else { if ($_SERVER["HTTP_X_FORWARDED_FOR"] && strcasecmp($_SERVER["HTTP_X_FORWARDED_FOR"], "unknown")) { $ip = $_SERVER["HTTP_X_FORWARDED_FOR"]; } else { if ($_SERVER["REMOTE_ADDR"] && strcasecmp($_SERVER["REMOTE_ADDR"], "unknown")) { $ip = $_SERVER["REMOTE_ADDR"]; } else { if (isset ($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], "unknown") ) { $ip = $_SERVER['REMOTE_ADDR']; } else { $ip = "unknown"; } } } } return ($ip); } echo getIp(); 

測試

curl偽造IP請求:

$ch = curl_init('http://localhost/ip.php'); //通用設置 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);//不直接輸出 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);//跟蹤重定向 //偽造請求頭 $ip = mt_rand(1, 255) . '.' . mt_rand(1, 255) . '.' . mt_rand(1, 255) . '.' . mt_rand(1, 255); $header = [ 'CLIENT-IP: ' . $ip, 'X-FORWARDED-FOR: ' . $ip, 'X-REAL-IP: ' . $ip, 'Accept-Language: zh-CN,zh;', ]; curl_setopt($ch, CURLOPT_HTTPHEADER, $header); $html = curl_exec($ch); curl_close($ch); echo $html; 

輸出SERVER數組,發現【HTTP_CLIENT_IP】、【HTTP_X_FORWARDED_FOR】、【HTTP_X_REAL_IP】是隨機變動的IP地址。

主流方法根本不安全!

分析

為什么?

HTTP_CLIENT_IP:存在於http請求的header
HTTP_X_FORWARDED_FOR:請求轉發路徑,客戶端IP,代理1IP,代理2IP......
HTTP_X_REAL_IP:這個用得比較少,暫不討論。

這三個值都是從HTTP請求頭獲取的,所以並不可靠!

REMOTE_ADDR

REMOTE_ADDR:是直接從TCP中獲取的IP,基本不會被偽造!

返回查看$_SERVER數組,發現【REMOTE_ADDR】顯示正確的IP!

所以直接用 $_SERVER['REMOTE_ADDR'] 就解決問題了?

其實還不行,如果客戶端和服務器之間存在代理服務器,【REMOTE_ADDR】的值是最后一個代理服務器的IP!

只有第一台接收客戶端請求的代理服務器的【REMOTE_ADDR】值才是客戶的真實IP地址,要把該值傳遞下去!

解決方案

1. 客戶端和服務器直連

<?php
function get_client_ip() { $ip = $_SERVER['REMOTE_ADDR']; return $ip; } 

2. 客戶端和服務器存在中間代理

第一層nginx代理設置:

proxy_set_header X-Forwarded-For $remote_addr;

其他層nginx代理設置:

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

PHP代碼:

<?php
function get_client_ip() { $ip = null; if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { $ip = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']); $ip = trim(current($ip)); } return $ip; }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM