Nginx 反向代理預設會將客戶端 IP 覆蓋為代理伺服器 IP。需透過 --with-http_realip_module 編譯模組,配合 proxy_set_header 將真實 IP 傳遞給上游:
X-Real-IP:固定為直接下游的 IP(最可信)X-Forwarded-For:追蹤完整代理鏈路,格式 client, proxy1, proxy2..../configure \
--prefix=/data/nginx \
--with-http_realip_module \
--with-stream \
--with-pcre=/tmp/X/pcre-8.32 \
--with-openssl=/tmp/X/openssl-1.0.2a
驗證編譯結果:
nm nginx | grep realip
# 0809c54b t ngx_http_realip
location / {
proxy_pass https://20.61.28.11:80;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr; # 必須
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
proxy_set_header 可置於 http/server/location,層層繼承覆蓋。
#include <stdio.h> #include <stdlib.h>
int main() {
printf("Content-Type:text/html;charset=utf-8\r\n\r\n");
printf("<p>HTTP_X_FORWARDED_FOR:%s\n", getenv("HTTP_X_FORWARDED_FOR"));
printf("<p>HTTP_X_REAL_IP:%s\n", getenv("HTTP_X_REAL_IP"));
printf("<p>REMOTE_ADDR:%s\n", getenv("REMOTE_ADDR"));
return 0;
}
| 場景 | X-Forwarded-For | X-Real-IP | REMOTE_ADDR |
|---|---|---|---|
| 正常請求 | 10.6.81.39, 10.6.223.44 | 10.6.223.44 | 10.6.81.39 |
| Client 偽造 Header | 8.8.8.7, 10.6.81.39, 10.6.223.44 | 10.6.223.44 | 8.8.8.7 |
| Nginx-A 不傳 XFF | 10.6.223.44 | 10.6.223.44 | 10.6.223.44 |
| Nginx-B 不傳 XFF | 10.6.81.39 | 10.6.223.44 | 10.6.81.39 |
| 場景 | X-Forwarded-For | X-Real-IP | REMOTE_ADDR |
|---|---|---|---|
| 正常請求 | 10.6.81.39 | 10.6.81.39 | 10.6.81.39 |
| Client 偽造 Header | 8.8.8.7, 10.6.81.39 | 10.6.81.39 | 8.8.8.7 |
HTTP_X_REAL_IP 直接可得真實 Client IPHTTP_X_FORWARDED_FOR 的第一個值REMOTE_ADDR 完全可被 Client 竄改(如測試 B 所示)HTTP_X_REAL_IP 永遠為 Nginx 直接下游真實 IP,無法偽造X-Forwarded-For 永遠包含真實 Client IP(取第一個)X-Real-IP(單層)或解析 X-Forwarded-For 首段(多層)real_ip_header X-Real-IP; 與 set_real_ip_from 信任內部代理 CIDR,自動重寫 $remote_addrX-Forwarded-For,防止 IP 偽造攻擊