代理後端的 Nginx 限制真實客戶端IP訪問問題
一、背景–當前問題
1、正常情況,nginx 限制ip訪問方式:
# nginx http\server 塊中配置
allow 192.168.6.0/16;
# allow all;
deny 1.2.3.4/32;
# deny all;
2、當nginx經過前端 elb(aws負載均衡)、cdn等代理後,來源IP總是elb、cdn等代理 IP地址
當 nginx處於前端負載均衡、cdn等代理後面,來源IP總是代理IP,這樣就無法如上對來源IP進行限制訪問。
如這裡: AWS ELB 後端獲取真實客戶端IP地址配置,可以獲取到來源IP地址,不過只是顯示看的,來源IP仍是elb、cdn等IP。
二、 解決方案
既然已經拿到使用者真實 IP 地址了,稍加配置,就可以了。
1、在 Nginx 的 http 模組內加入如下配置:
# 獲取使用者真實IP,並賦值給變數$clientRealIP
map $http_x_forwarded_for $clientRealIp {
"" $remote_addr;
~^(?P<firstAddr>[0-9\.]+),?.*$ $firstAddr;
}
那麼,$clientRealIP
就是使用者真實 IP 了,其實就是匹配了 $http_x_forwarded_for
其實,當一個 CDN 或者透明代理伺服器把使用者的請求轉到後面伺服器的時候,這個 CDN 伺服器會在 Http 的頭中加入一個記錄
X-Forwarded-For : 使用者 IP, 代理伺服器 IP
如果中間經歷了不止一個代理伺服器,這個記錄會是這樣
X-Forwarded-For : 使用者 IP, 代理伺服器 1-IP, 代理伺服器 2-IP, 代理伺服器 3-IP, ….
可以看到經過好多層代理之後, 使用者的真實 IP 在第一個位置, 後面會跟一串中間代理伺服器的 IP 地址,從這裡取到使用者真實的 IP 地址,針對這個 IP 地址做限制就可以了。
而且程式碼中還配合使用了$remote_addr
,因此$clientRealIP
還能相容上文中第①種直接訪問模式,不像 $http_x_forwarded_for
在直接訪問模式中將會是空值!
所以,$clientRealIP
還能配置到 Nginx 日誌格式中,替代傳統的 $remote_addr
使用,推薦!
2、通過對 $clientRealIP
這個變數的判斷,實現限制訪問
nginx server 塊中
#如果真實IP為 121.42.0.18、121.42.0.19,那麼返回403
if ($clientRealIp ~* "121.42.0.18|121.42.0.19") {
#如果你的nginx安裝了echo模組,還能如下輸出語言,狠狠的發洩你的不滿(但不相容返回403,試試200吧)!
#add_header Content-Type text/plain;
#echo "son of a bitch,you mother fucker,go fuck yourself!";
return 403;
break;
}
把這個儲存為 deny_ip.conf ,上傳到 Nginx 的 conf 資料夾,然後在要生效的網站 server 模組中引入這個配置檔案,並 Reload 過載 Nginx 即可生效:
#禁止某些使用者訪問
include deny_ip.conf;