使用CDN(CloudFlare|騰訊雲|加速樂等)情況下如何獲取訪客真實IP ?
問題分析
網站使用了CloudFlare 或自建的CDN 方案,以加快網站的加載速度,但在觀察日誌發現,服務端獲取到的訪客IP 全都是CDN IP,而不是訪客的真實IP,這就導致無法實現分流或防護方案等高級功能。
技術背景
remote_addr
表示客戶端的IP,需要注意的是它的值是由連到服務器的客戶端提供的,也就是說,當你的瀏覽器直接訪問網站時,這個IP 就是你電腦的IP,當你使用了代理,那麼你的電腦就會先訪問這個代理,然後再由這個代理轉發請求到網站,此時對於服務器來說,連到服務器的客戶端是這個代理,所以這個IP 就會變成代理的IP,而不是你電腦的IP。開啟CDN 後,服務器只記錄到CDN IP 的原因也就是這個。
X-Forwarded-For
這是一個HTTP 的擴展頭部,HTTP/1.1 協議並沒有對它定義,它最開始是由Squid 這個緩存代理軟件引入,用來表示HTTP 請求端的真實IP。如今已經成為事實上的標準,被各大HTTP代理、負載均衡等轉發服務廣泛使用,並已寫入標準之中。
XFF(X-Forwarded-For)的格式為:
X-Forwarded-For: client, proxy1, proxy2
由英文逗號+空格隔開的多個部分組成,最開始的是離服務器最遠的設備IP(可以認為是真實客戶端),然後經過每一級的IP(中間內容是可以被偽造)。
X-Real_IP
同樣是一個自定義頭部字段,通常被HTTP 代理用來表示與它產生TCP 連接的設備IP,這個設備可能是代理IP,也可能是用戶IP。
環境模擬
192.168.1.100(用户内网 IP) ⇌ 192.168.1.1/1.1.1.1(局域网的网关 IP 与路由器的公网 IP) ⇌ 2.2.2.2(负载均衡或者 CDN 服务器 IP) ⇌ 3.3.3.3(服务器 IP)
以上基本上就是使用CDN 後的整個瀏覽網站行為路線,這種情況下,如果2.2.2.2 會把1.1.1.1 的IP 信息添加到附加信息傳遞給服務器3.3.3.3(實際情況中很少會關注內網IP 是什麼,這裡不做介紹),服務取得的IP 就是1.1.1.1;如果2.2.2.2 沒有把1.1.1.1 附加傳遞給服務器3.3.3.3,則服務器就只能獲取到其上一級的IP 2.2.2.2。
獲取真實IP
根據技術背景中提到的,
①當我們的服務器直接暴露在公網上,並未使用CDN和代理服務器時,是可以直接使用 remote_addr
參數來獲取用戶IP。比如PHP中可以直接使用 '$_SERVER['REMOTE_ADDR']'
參數。
② 當我們使用了CDN 之後,一般CDN 的廠商都會把訪客真實IP 添加到XFF 中一層層傳遞下去,接下來我們要做的就是解決這種情況下,怎麼獲得訪客真實IP。
思路
上面說到XFF 與X-Real-IP 是可以偽造的,但remote_addr 是客戶端與服務器的握手IP,是無法偽造的。我們可以使用curl 偽造XFF 與X-Real-IP 先來測試下,客戶端IP 為192.168.1.6, 服務端IP 為192.168.1.135:
curl http://192.168.1.135 -H 'X-Forwarded-For: unkonw, <alert>aa,1.1.1.1</alert>" 1.1.1.1' -H 'X-Real-IP: 2.2.2.2, <a>'
在服務器中使用tcpdump 抓包, 然後打開Wireshark 分析請求頭部信息,可以看到:
Hypertext Transfer Protocol
GET / HTTP/1.1\r\n
User-Agent: curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2\r\n
Host: 192.168.1.135\r\n
Accept: */*\r\n
X-Forwarded-For: unkonw, <alert>aa,1.1.1.1</alert>" 1.1.1.1\r\n
X-Real-IP: 2.2.2.2, <a>\r\n
\r\n
[Full request URI: http://192.168.1.135/]
[HTTP request 1/1]
可以看出,它記錄了我們偽造的信息,所以XFF 與X-Real-IP 是不可以直接拿來用的。我們可以把各個代理層的IP 使用排除法排除在外,那麼剩下的便是用戶的真實IP 了。
配置
Nginx
使用Nginx的RealIP模塊來實現自動排除,在編譯時(或重新編譯)加上 -with-http_realip_module
就可以了,具體方法可以參考《建站系列之為Nginx安裝GeoIP模塊實現分流或屏蔽某個地區訪問》,然後在Nginx配置中加入:
......
set_real_ip_from 2a06:98c0::/29;
set_real_ip_from 37.0.121.100;
real_ip_header CF-Connecting-IP;
real_ip_recursive on;
......
說明:
- set_real_ip_from: 後面是可信IP,如果是使用CDN,則是CDN IP;
- real_ip_header: 表示從哪個header 中獲取IP 信息;
- real_ip_recursive: 遞歸排除IP,IP 串從右到左開始排除。
Nginx 與代理IP 有關的兩個變量:
- $proxy_add_x_forwarded_for:會累加代理層的IP 向後傳遞;
- $http_x_forwarded_for 僅僅是上層傳過來的值;
Apache
Apache 有兩個模塊來獲取真實IP:
- mod_rpaf:Apache-2.2 支持,apache-2.4 不支持
- mod_remoteip:Apache-2.4 自帶模塊,apache-2.2 支持
mod_rpaf 實際使用已經過測試,mod_remoteip 還未實際測試,如遇到有問題會再修改。
配置mod_rpaf 模塊(需要自行安裝)
LoadModule rpaf_module modules/mod_rpaf-2.0.so
RPAFenable On
RPAFsethostname On
RPAFproxy_ips 127.0.0.1 10.8.0.110 #代理服务器的 IP 地址
RPAFheader X-Forwarded-For
備註:RPAFproxy_ips 後面添加代理服務器的IP,有多少個寫多少個。
配置mod_remoteip 模塊
# vim /usr/local/apache/conf/extra/httpd-remoteip.conf
......
LoadModule remoteip_module modules/mod_remoteip.so
RemoteIPHeader X-Forwarded-For
RemoteIPInternalProxy 127.0.0.1
......
附錄
各大CDN 的節點IP 段
騰訊雲CDN
58.250.143.0/24
58.251.121.0/24
59.36.120.0/24
61.151.163.0/24
101.227.163.0/24
111.161.109.0/24
116.128.128.0/24
123.151.76.0/24
125.39.46.0/24
140.207.120.0/24
180.163.22.0/24
183.3.254.0/24
223.166.151.0/24
加速樂CDN
113.107.238.0/24
106.42.25.0/24
183.222.96.0/24
117.21.219.0/24
116.55.250.0/24
111.202.98.0/24
111.13.147.0/24
122.228.238.0/24
58.58.81.0/24
1.31.128.0/24
123.155.158.0/24
106.119.182.0/24
180.97.158.0/24
113.207.76.0/24
117.23.61.0/24
118.212.233.0/24
111.47.226.0/24
219.153.73.0/24
113.200.91.0/24
1.32.240.0/24
203.90.247.0/24
183.110.242.0/24
202.162.109.0/24
182.23.211.0/24
1.32.242.0/24
1.32.241.0/24
202.162.108.0/24
185.254.242.0/24
109.94.168.0/24
109.94.169.0/24
1.32.243.0/24
61.120.154.0/24
1.255.41.0/24
112.90.216.0/24
61.213.176.0/24
1.32.238.0/24
1.32.239.0/24
1.32.244.0/24
百度雲CDN
111.32.135.0/24
111.32.136.0/24
125.39.174.0/24
125.39.239.0/24
112.65.73.0/24
112.65.74.0/24
112.65.75.0/24
119.84.92.0/24
119.84.93.0/24
113.207.100.0/24
113.207.101.0/24
113.207.102.0/24
180.163.188.0/24
180.163.189.0/24
163.53.89.0/24
101.227.206.0/24
101.227.207.0/24
119.188.97.0/24
119.188.9.0/24
61.155.149.0/24
61.156.149.0/24
61.155.165.0/24
61.182.137.0/24
61.182.136.0/24
120.52.29.0/24
120.52.113.0/24
222.216.190.0/24
219.159.84.0/24
183.60.235.0/24
116.31.126.0/24
116.31.127.0/24
117.34.13.0/24
117.34.14.0/24
42.236.93.0/24
42.236.94.0/24
119.167.246.0/24
150.138.149.0/24
150.138.150.0/24
150.138.151.0/24
117.27.149.0/24
59.51.81.0/24
220.170.185.0/24
220.170.186.0/24
183.61.236.0/24
14.17.71.0/24
119.147.134.0/24
124.95.168.0/24
124.95.188.0/24
61.54.46.0/24
61.54.47.0/24
101.71.55.0/24
101.71.56.0/24
183.232.51.0/24
183.232.53.0/24
157.255.25.0/24
157.255.26.0/24
112.25.90.0/24
112.25.91.0/24
58.211.2.0/24
58.211.137.0/24
122.190.2.0/24
122.190.3.0/24
183.61.177.0/24
183.61.190.0/24
117.148.160.0/24
117.148.161.0/24
115.231.186.0/24
115.231.187.0/24
牛盾CDN
113.31.27.0/24
222.186.19.0/24
122.226.182.0/24
36.99.18.0/24
123.133.84.0/24
221.204.202.0/24
42.236.6.0/24
61.130.28.0/24
61.174.9.0/24
223.94.66.0/24
222.88.94.0/24
61.163.30.0/24
223.94.95.0/24
223.112.227.0/24
183.250.179.0/24
120.241.102.0/24
125.39.5.0/24
124.193.166.0/24
122.70.134.0/24
111.6.191.0/24
122.228.198.0/24
121.12.98.0/24
60.12.166.0/24
118.180.50.0/24
183.203.7.0/24
61.133.127.0/24
113.7.183.0/24
210.22.63.0/24
60.221.236.0/24
122.227.237.0/24
360 CDN
123.6.13.0/24
202.102.85.0/24
61.160.224.0/24
182.140.227.0/24
221.204.14.0/24
222.73.144.0/24
61.240.144.0/24
36.27.212.0/24
125.88.189.0/24
120.52.18.0/24
119.84.15.0/24
180.163.224.0/24
CloudFlare CDN
103.21.244.0/22
103.22.200.0/22
103.31.4.0/22
104.16.0.0/12
108.162.192.0/18
131.0.72.0/22
141.101.64.0/18
162.158.0.0/15
172.64.0.0/13
173.245.48.0/20
188.114.96.0/20
190.93.240.0/20
197.234.240.0/22
198.41.128.0/17
2400:cb00::/32
2405:b500::/32
2606:4700::/32
2803:f800::/32
2c0f:f248::/32
2a06:98c0::/29