透傳IP
為何要做透傳IP
在使用了CDN
做加速站點靜態資源加速后,當用戶請求的靜態資源沒能命中,此時CDN
會到源站請求內容,那么此時訪問源站的IP
為CDN
節點的IP
,不僅如此,可能經我們的WAF
防火牆和前端的負載均衡(SLB
)后更不容易獲取到真實的用戶IP
信息,我們如果要統計用戶的訪問IP
和地區就變得比較麻煩,因為可能不是真實的IP
,必須使用一個什么機制將用戶IP
傳遞到最終后端的應用服務器才行。
實驗環境
訪問流程
主機 | IP配置 | 備注 |
---|---|---|
Chrome |
10.0.0.1 |
Windows 瀏覽器 |
LB-01 |
10.0.0.5 |
一級代理 |
LB-02 |
10.0.0.6 |
二級代理 |
LB-03 |
10.0.0.7 |
三級代理 |
WEB |
10.0.0.8 |
WEB主機 |
常見的幾種方式
X-Real-IP
描述
在每個HTTP
請求頭中加入X-Real-IP
信息,若只存在1級的代理服務器,則該參數的確就是客戶端的真實IP
,但若是存在多級代理時,此信息為上級代理的IP
信息,並不能獲取到真實的用戶IP
,故此法目前已棄用。
nginx配置
#LB-01一級代理配置
server {
listen 80;
server_name ip.test.com;
location / {
proxy_pass http://10.0.0.6;
proxy_http_version 1.1;
Proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
}
}
#LB-02二級代理配置
server {
listen 80;
server_name ip.test.com;
location / {
proxy_pass http://10.0.0.7;
proxy_http_version 1.1;
Proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
}
}
#LB-03三級代理配置
server {
listen 80;
server_name ip.test.com;
location / {
proxy_pass http://10.0.0.8;
proxy_http_version 1.1;
Proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
}
}
#WEB主機配置
server {
listen 80;
server_name ip.test.com;
root /wwwroot;
index index.php;
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
WEB主機測試腳本
#文件名:index.php
#放到測試目錄/wwwroot內
<?php
$IP_ADDRESS = getenv("HTTP_X_REAL_IP");
echo "SOURCE IP ADDRESS: $IP_ADDRESS";
?>
注:配置完成后保存所有配置文件,然后啟動所有的nginx
服務。如果在windows
下測試一定要在C:\Windows\System32\drivers\etc\hosts
文件內加入本地解析的記錄,如下:
10.0.0.5 ip.test.com
Wireshark抓包信息
HTTP報頭信息
GET / HTTP/1.1
Host: ip.test.com
X-Real-IP: 10.0.0.6
Connection: close
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: UM_distinctid=16afc8d323f94-0360d7ebcc9bae-3d644509-18e414-16afc8d324063f
chrome打開測試
結論:由Wireshark
追蹤流和Chrome
的測試可見,X-Real-IP
並不能獲取到真實的客戶端IP
地址,如果時單級代理情況下,可以獲取到正確的客戶端IP
,若存在多級代理就歇菜了。
X-Forwarded-For
描述
在每個HTTP
請求頭中加入X-Forwarded-For
信息,若只存在1級的代理服務器,則該參數為客戶端的真實IP
,若是存在多級代理時,每經過一級代理服務器,則追加上級代理服務的IP
,可以獲取到真實的用戶IP
,但若是遇到偽造的X-Forwarded-For
信息或第一級代理未啟用X-Forwarded-For
都不能獲取到真實用戶IP
,此法是目前比較常用的方法,但更推薦使用nginx_http_realip_module
模塊添加可信代理的方法。
nginx配置
#LB-01一級代理配置
server {
listen 80;
server_name ip.test.com;
location / {
proxy_pass http://10.0.0.6;
proxy_http_version 1.1;
Proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#可以嘗試注釋此處的,看看最終能否獲取到真實客戶端IP
}
}
#LB-02二級代理配置
server {
listen 80;
server_name ip.test.com;
location / {
proxy_pass http://10.0.0.7;
proxy_http_version 1.1;
Proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
#LB-03三級代理配置
server {
listen 80;
server_name ip.test.com;
location / {
proxy_pass http://10.0.0.8;
proxy_http_version 1.1;
Proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
#WEB主機配置
server {
listen 80;
server_name ip.test.com;
root /wwwroot;
index index.php;
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
WEB主機測試腳本
#文件名:index.php
#放到測試目錄/wwwroot內
<?php
$IP_ADDRESS = getenv("HTTP_X_FORWARD_FOR");
echo "SOURCE IP ADDRESS: $IP_ADDRESS";
?>
注:記得重載nginx
配置。
Wireshark抓包信息
HTTP報頭信息
GET / HTTP/1.1
Host: ip.test.com
X-Forwarded-For: 10.0.0.1, 10.0.0.5, 10.0.0.6
Connection: close
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: UM_distinctid=16afc8d323f94-0360d7ebcc9bae-3d644509-18e414-16afc8d324063f
chrome打開測試
結論:由Wireshark
追蹤流和Chrome
的測試可見,X-Forwarded-For
可以獲取到真實的客戶端IP
地址,即便是在多級代理下,也可以獲取到正確的客戶端IP
,但如果某台代理未設置X-Forwarded-For
,后端應用服務器可能並不能獲取到正確的客戶端IP
。
nginx_http_realip_module
描述
通過預定義可信任的代理主機的IP
的方式(可信代理主機默認都會加入X-Forwarded-For
信息),根據些X-Forwarded-For
的信息,從右到左,濾除掉這些可信代理的IP
信息,最終獲取到的就是真實客戶端IP
信息,此信息替換$remote_addr
這個變量,使最終客戶端IP
在WEB
后端應用服務器的access.log
第一列顯示,方便取值分析。
nginx配置
#LB-01一級代理配置
server {
listen 80;
server_name ip.test.com;
location / {
proxy_pass http://10.0.0.6;
proxy_http_version 1.1;
Proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#此為可信任的代理服務器,故需要加入這條配置
}
}
#LB-02二級代理配置
server {
listen 80;
server_name ip.test.com;
location / {
proxy_pass http://10.0.0.7;
proxy_http_version 1.1;
Proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#此為可信任的代理服務器,故需要加入這條配置
}
}
#LB-03三級代理配置
server {
listen 80;
server_name ip.test.com;
location / {
proxy_pass http://10.0.0.8;
proxy_http_version 1.1;
Proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#此為可信任的代理服務器,故需要加入這條配置
}
}
#WEB主機配置,使用此模塊是在后端WEB應用服務器添加參數
server {
listen 80;
server_name ip.test.com;
#定義可信任的代理服務器地址
set_real_ip_from 10.0.0.5;
set_real_ip_from 10.0.0.6;
set_real_ip_from 10.0.0.7;
#指定從哪個HTTP報頭里檢索IP信息
real_ip_header X-Forwarded-For;
#遞歸排除每個代理服務器的IP
real_ip_recursive on;
root /wwwroot;
index index.php;
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
WEB主機測試腳本
#文件名:index.php
#放到測試目錄/wwwroot內
<?php
$IP_ADDRESS = getenv("HTTP_X_FORWARD_FOR");
echo "SOURCE IP ADDRESS: $IP_ADDRESS";
?>
注:記得重載nginx
配置。
Wireshark抓包信息
HTTP報頭信息
GET / HTTP/1.1
Host: ip.test.com
X-Forwarded-For: 10.0.0.1, 10.0.0.5, 10.0.0.6
Connection: close
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: UM_distinctid=16afc8d323f94-0360d7ebcc9bae-3d644509-18e414-16afc8d324063f
chrome打開測試
WEB應用服務器的訪問LOG
結論:為了解決X-Forwarded-For
可能存在偽裝IP
的問題,我們在后端使用了nginx_http_realip_module
模塊的set_real_ip_from
關鍵字來添加可信IP
並從X-Forwarded-For
頭中篩選出去,最終成功獲取到了客戶端IP
,並且也對格式日志做了一定的替換,使客戶端IP
顯示於access.log
的第一列,方便最終的取值分析,這里需要注意的是,一定要添加正確且絕對可信的代理服務器IP
,否則最終結果還是存在問題。