我們都知道,在Nginx中,想獲取來源的IP,我們可以通過$remote_addr
來獲取,但是很多時候,請求會經過多箇中間代理或CDN,從而導致我們根本無法準確的獲取客戶端的真實IP, 爲解決這種問題,Nginx提供了realip模塊來實現客戶端IP的獲取,詳細信息參見:ngx_http_realip_module
此模塊提供了三個指令:set_real_ip_from
, real_ip_header
,real_ip_recursive
,其功能如下:
- set_real_ip_from:指定IP的來源信息,用於排除中間代理IP,可以填寫IP或網段。
- real_ip_header:指定從Header的哪個屬性裏面取IP信息,常用的是
X-Forwarded-For
- real_ip_recursive:是否遞歸的排除中間代理IP信息,默認值爲off,如果值設置爲off,則只會排除直接上層代理的IP信息,如果值爲on,則會從右至左依次排除用戶配置的中間IP,直到遇到第一個非指定的IP,將此IP設置爲真實IP。
雖然只有三個指令,但是其功能都是比較晦澀難懂的,下面我通過一個實驗,來揭示此模塊的功能及用法:
實現環境:
-
訪問源IP:10.38.160.252
-
代理一:10.38.165.227(四層代理,非Nginx),其後端指向代理二的三臺機器
-
代理二:
- 10.38.160.94
- 10.38.160.101
- 10.38.160.96
-
代理三:10.38.160.174
-
代理四:10.232.51.224
-
目的:10.232.51.224: 8090
連接過程示意圖:
Nginx關鍵配置內容:
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-For $remote_addr
-
remote_addr:遠程地址,如果未經處理,此值爲與Nginx直接連接的上層的IP地址
-
proxy_add_x_forwarded_for:其值爲 從上一代理獲取到的 X-Forwarded-For 值 追加上 remote_addr 的值,中間使用,分割
能獲取到客戶端真實IP的條件如下:
- 所有七層代理(代理2-3) 需要配置如下配置,以使其可以完整記錄經過各個代理時的真實IP信息
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- 末端代理(代理4)需要配置如下配置,過濾掉中間配置
set_real_ip_from 10.38.160.94; // 過濾代理2
set_real_ip_from 10.38.160.101; // 過濾代理2
set_real_ip_from 10.38.160.96; // 過濾代理2
set_real_ip_from 10.38.160.174; // 過濾代理3
real_ip_header X-Forwarded-For; // 指定從哪個header裏面取real ip
real_ip_recursive on; // 是否遞歸查找
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr; // 通過上面配置,最終Realip會被存儲在$remote_addr中
通過如上的配置,我們就可以實現對真實IP的獲取,真實IP就存儲在 X-Real-IP 中
問題:
- 如果條件1不滿足呢?
如果所有都沒有配置X-Forwarded-For,那將無法獲取到真實IP,只能獲取到代理3的IP,如果部分節點設置了,只能獲取到第一個設置的節點的上一個節點的IP信息,如從代理3開始設置了,那獲取到的 realip 只能獲取到代理2的IP信息
- 如果 real_ip_recursive爲off或不設置呢?
如果 real_ip_recursive未設置或值不爲on,那麼即使set_real_ip_from設置了很多,也只會去除上個節點的IP信息,如我在代理4設置瞭如下信息:
set_real_ip_from 10.38.160.94;
set_real_ip_from 10.38.160.101;
set_real_ip_from 10.38.160.96;
set_real_ip_from 10.38.160.174;
real_ip_header X-Forwarded-For;
real_ip_recursive off;
proxy_set_header X-Real-IP $remote_addr;
那麼,獲取到的真實IP只會是代理2中的任意一個,即:10.38.160.94、10.38.160.101 或 10.38.160.96,即使set_real_ip_from設置了這三個IP,但是還是不會繼續往上遞歸去除,只會對上個節點起作用
- 如果set_real_ip_from沒有設置,或設置不完全呢?
set_real_ip_from的功能是從X-Forwarded-For中去除掉中間層IP信息,如果中間IP設置不全,則會導致某個未設置的中間IP被當成客戶端真實IP