1. 程式人生 > >代理後端的 Nginx 限制真實客戶端IP訪問問題

代理後端的 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;