nginx反向代理后,在應用中取得的ip都是反向代理服務器的ip,取得的域名也是反向代理配置的url的域名,解決該問題,需要在nginx反向代理配置中添加一些配置信息,目的將客戶端的真實ip和域名傳遞到應用程序中。
①:php獲取REMOTE_ADDR就是這樣一個情況(內網地址)。
②:獲取的是攻擊者偽造的ip地址。攻擊者可以隨便偽造一個頭部信息,隨便填寫一個ip放到頭部發過來,php獲取到HTTP_CLIENT_IP就是這樣一個情況。偽造的ip,導致我們數據庫存儲是假的ip,無從真實去判斷攻擊者的來源。比如批量注冊帳號的注冊ip,登錄的ip等。
配置如下:
location ~* \.(jpg|png|gif)$ { proxy_set_header X-Forwarded-For $remote_addr; #proxy_pass http://....
} location ~ \.php$ { proxy_set_header X-Forwarded-For $remote_addr; #proxy_pass http://....
}
PHP代碼:
function getIP() { $ip = "unknown"; 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"); } return $ip; }
總結
在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地址。
php獲取用戶IP地址的三個屬性的區別
下面分析獲得IP的幾種情況。
一、沒有使用代理服務器的情況:
REMOTE_ADDR = 您的 IP
HTTP_VIA = 沒數值或不顯示
HTTP_X_FORWARDED_FOR = 沒數值或不顯示
二、使用透明代理服務器的情況:Transparent Proxies
REMOTE_ADDR = 最后一個代理服務器 IP
HTTP_VIA = 代理服務器 IP
HTTP_X_FORWARDED_FOR = 您的真實 IP ,經過多個代理服務器時,這個值類似如下:203.98.182.163, 203.98.182.163, 203.129.72.215。
這類代理服務器還是將您的信息轉發給您的訪問對象,無法達到隱藏真實身份的目的。
三、使用普通匿名代理服務器的情況:Anonymous Proxies
REMOTE_ADDR = 最后一個代理服務器 IP
HTTP_VIA = 代理服務器 IP
HTTP_X_FORWARDED_FOR = 代理服務器 IP ,經過多個代理服務器時,這個值類似如下:203.98.182.163, 203.98.182.163, 203.129.72.215。
隱藏了您的真實IP,但是向訪問對象透露了您是使用代理服務器訪問他們的。
四、使用欺騙性代理服務器的情況:Distorting Proxies
REMOTE_ADDR = 代理服務器 IP
HTTP_VIA = 代理服務器 IP
HTTP_X_FORWARDED_FOR = 隨機的 IP ,經過多個代理服務器時,這個值類似如下:203.98.182.163, 203.98.182.163, 203.129.72.215。
告訴了訪問對象您使用了代理服務器,但編造了一個虛假的隨機IP代替您的真實IP欺騙它。
五、使用高匿名代理服務器的情況:High Anonymity Proxies (Elite proxies)
REMOTE_ADDR = 代理服務器 IP
HTTP_VIA = 沒數值或不顯示
HTTP_X_FORWARDED_FOR = 沒數值或不顯示 ,經過多個代理服務器時,這個值類似如下:203.98.182.163, 203.98.182.163, 203.129.72.215。
完全用代理服務器的信息替代了您的所有信息,就象您就是完全使用那台代理服務器直接訪問對象。
返回一個ip
public static function getIP() { if (!empty($_SERVER["HTTP_CLIENT_IP"])) { $cip = $_SERVER["HTTP_CLIENT_IP"]; } else if (!empty($_SERVER["HTTP_X_FORWARDED_FOR"])) { $cip = $_SERVER["HTTP_X_FORWARDED_FOR"]; } else if (!empty($_SERVER["REMOTE_ADDR"])) { $cip = $_SERVER["REMOTE_ADDR"]; } else { $cip = ''; } preg_match("/[\d\.]{7,15}/", $cip, $cips); $cip = isset($cips[0]) ? $cips[0] : 'unknown'; unset($cips); return $cip; }
