壹
HTTP擴展頭部 X-Forwarded-For,以及在nginx中使用http_x_forwarded_for變量來完成一些"特殊"功能,例如網站后台面向內部工作人員,希望只允許辦公室網絡IP訪問。
X-Forwarded-For,它用來記錄代理服務器的地址,每經過一個代理該字段會追加上一個記錄。例如:6.6.6.6, 8.8.8.8。
貳
拿出生產環境的一個例子,客戶端瀏覽網站發出一個請求,請求先經過阿里雲SLB負載均衡器,然后進入Rancher內部的LB負載均衡器,經過兩次負載均衡器轉發后請求到達nginx服務器。

叄
X-Forwarded-For HTTP擴展頭部
日志中的記錄表示 client: 101.251.xxx.192 、proxy1: 100.97.xxx.187,不是說 X-Forwarded-For用來記錄代理服務器的地址,每經過一個代理該字段會追加上一個記錄,為什么client IP 會出現在這個字段中呢?
帶着疑惑這里有必要專門講一講 X-Forwarded-For HTTP頭部。X-Forwarded-For 是一個 HTTP擴展頭部,HTTP/1.1(RFC 2616)協議並沒有對它的定義,它最開始是由 Squid緩存代理軟件引入,用來表示 HTTP請求端真實IP。最終成為事實上的標准被寫入 RFC 7239(Forwarded HTTP Extension)標准之中。
X-Forwarded-For 標准格式
X-Forwarded-For: client, proxy1, proxy2
從標准格式可以看出,X-Forwarded-For頭部信息可以有多個,中間使用逗號分隔,第一項為真實的客戶端IP,剩下的就是經過的代理或負載均衡的IP地址,經過幾個就會出現幾個。
回到上面的示例,HTTP請求到達nginx服務器之前,經過了兩個代理Proxy1、Proxy2,IP 分別為IP1、IP2,用戶真實IP為 IP0,那么按照 XFF標准格式,nginx服務器最終的XFF變量如下:
X-Forwarded-For: IP0, IP1
Proxy2是直連服務器的,它會給 XFF追加IP1,表示它是在幫 Proxy1轉發請求,IP2是在服務端通過 Remote Address 獲得。Remote Address 也無法偽造,因為建立TCP連接需要三次握手,如果偽造了源IP,無法建立TCP連接,更不會有后面的 HTTP請求。
肆
nginx 中的 http_x_forwarded_for 變量用來表示 X-Forwarded-For ,下面用一個例子說明 nginx 如何使用 http_x_forwarded_for,例如借用這個變量限制網站后台訪問。
1. 環境
browser -> haproxy -> nginx
目標判斷 haproxy負載均衡傳遞的 http_x_forwarded_for變量,確定是否為辦公室IP?是否允許訪問網站后台?
2. 方法
a. 修改 nginx 虛擬主機配置文件,添加以下語句。
cat default.conf server { #... 其它配置項省略 location ^~ /admin/ { if ($http_x_forwarded_for !~ 'your_office_ip') { return 403; } #... 其它配置項省略 } }
b. 重新加載
nginx -t && nginx -s reload
c. 偽造XFF
需要特別說明的是XFF是可以偽造的,例如使用curl 發送一個帶有"X-Forwarded-For:8.8.8.8"的頭部信息。
curl -IL -H "X-Forwarded-For:8.8.8.8" https://www.test.com/static/09.png
假設你采用XFF對比IP方式來限制網站后台訪問,如果對方知道你的網站在用這個策略限制后台訪問,並且通過一些方法知道了你辦公室的IP地址,那么這個策略也就失效了。如果你的網站"前后台"可以分離,那么可以為分離后的后台服務器添加防火牆規則,通過網絡層限制來源IP地址達到同樣目的。