Nginx 限制單個IP的併發連接數【支持CDN 站點】

上次文章【Nginx 限制單個IP的併發連接數/速度來減緩垃圾蜘蛛爬蟲採集】裏介紹的辦法明月感覺還是很有效的,特別是那些垃圾爬蟲頻繁抓取有一定的遏制,但是有一個不足的地方就是在站點開啓 CDN 後因爲有了 CDN 節點代理的存在,造成屏蔽的IP都是 CDN 節點的IP,誤傷率太高了,明顯的不科學呀!

nginx.jpg

在度娘、谷姐了一番後,明月終於還是找到了有效的辦法來應對這個問題了(這裏不得不吐槽一下網上“水文”質量真的是太差了,轉載抄襲的實在是太嚴重了,代碼混亂不堪,幾乎沒有一篇文章的代碼是可以直接使用的!),今天就繼續給大家分享一下。

Nginx 有 2 個模塊用於控制訪問“數量”和“速度”,簡單的說,控制你最多同時有 多少個訪問,並且控制你每秒鐘最多訪問多少次, 你的同時併發訪問不能太多,也不能太快,不然就“殺無赦”。

  • HttpLimitZoneModule 限制同時併發訪問的數量
  • HttpLimitReqModule 限制訪問數據,每秒內最多幾個請求

關於這兩個Nginx模塊的使用在【Nginx 限制單個IP的併發連接數/速度來減緩垃圾蜘蛛爬蟲採集】一文裏,明月已經給大家講述過了,也實施應用了。今天我們要講的是如何在站點開啓了 CDN 後來根據真實IP(非 CDN 節點IP)來限制併發連接和限速。

很多時候,我們的網站不是簡單的:普通用戶IE瀏覽器 ——-> 你的服務器 的結構, 考慮到網絡訪問速度問題,我們中間可能會有各種 網絡加速(CDN)。以我的博客網站 www.imydl.com 爲例,考慮到網站的安全性和訪問加速,我們的架構是:

普通用戶瀏覽器 —–> 360網站衛士加速(CDN,360防 CC,DOS攻擊) ——> 阿里雲加速服務器(我們自己建的CDN,阿里雲盾) —-> 源服務器(PHP 程序部署在這裏,iptables, nginx 安全配置)

可以看到,我們的網站中間經歷了好幾層的透明加速和安全過濾, 這種情況下,我們就不能用【Nginx 限制單個IP的併發連接數/速度來減緩垃圾蜘蛛爬蟲採集】一文裏的方法。因爲此文是基於 源IP的限制 結果就是,我們把 360網站衛士 或者 阿里雲盾 給限制了,因爲這裏“源IP”地址不再是 真實訪問者的IP,而是中間 網絡加速服務器 的IP地址。我們需要限制的是 最前面的真實訪問者(一般需要限制的都是些垃圾爬蟲、XLS掃描、漏洞掃描器等等),而不是中間爲我們做加速的 加速服務器

當一個 CDN 或者透明代理服務器把用戶的請求轉到後面服務器的時候,這個 CDN 服務器會在 Http 的頭中加入 一個記錄

X-Forwarded-For:用戶IP, 代理服務器IP

如果中間經歷了不止一個 代理服務器,像 www.imydl.com 中間建立多層代理之後,這個 記錄會是這樣

X-Forwarded-For : 用戶IP, 代理服務器1-IP, 代理服務器2-IP, 代理服務器3-IP, ….

 

可以看到經過好多層代理之後, 用戶的真實IP 在第一個位置, 後面會跟一串中間代理服務器的IP地址,從這裏取到用戶真實的IP地址,針對這個 IP 地址做限制就可以了。

那麼具體Nginx的配置裏可以通過如下的方式來獲取訪問者真實IP,而不是中間代理服務器的IP地址:

在nginx.conf的[http]模塊裏添加如下代碼

#獲取用戶真實IP,並賦值給變量$clientRealIP
map $http_x_forwarded_for  $clientRealIp {
        ""      $remote_addr;
        ~^(?P<firstAddr>[0-9\.]+),?.*$  $firstAddr;
}

通過 map 指令,我們爲 nginx 創建了一個變量 $clientRealIp ,這個就是 原始用戶的真實 IP 地址,不論用戶是直接訪問,還是通過一串 CDN 之後的訪問,我們都能取得正確的原始IP地址。

怎麼樣?很神奇吧,那麼具體這個有效與否呢,很簡單,利用Nginx的echo來測試一下即可。

在Nginx的站點配置文件裏[server]模塊里加上下面一段代碼:

server {
    listen   80;
        server_name  www.mydomain.com;
 
        #當用戶訪問 /nginx-test 的時候,我們輸出 $clientRealIp 變量,看看這個變量
        #值是不是真的 用戶源IP 地址
        location /nginx-test {
                echo $clientRealIp;
        }
}

接下來,用你的瀏覽器訪問 www.mydomain.com/nginx-test,這個時候會彈出框下載一個文件 nginx-test,下載完成用 notepad++ 打開,裏面就是一個 IP 地址,訪問 www.ipip.net ,看看這個裏面記錄的IP地址是否和 ip 偵測的IP 一致?

通過這種方式,你就可以對 Nginx 的一些複雜配置做有效的測試。

經過測試,我們確認 通過多層CDN 之後,$clientRealIp 仍然是有效的原始用戶IP地址。

下面就可以根據上述所獲得的 用戶真實 IP 做連接限制了:

在nginx.conf的[http]模塊裏添加如下代碼

#用戶的 IP 地址 $clientRealIP 作爲 Key,每個 IP 地址最多有 20 個併發連接
#你想開幾千個連接刷死我? 超過 20 個連接,直接返回 503 錯誤給你,根本不處理你的請求了
limit_conn_zone $clientRealIP zone=TotalConnLimitZone:10m ;
limit_conn  TotalConnLimitZone  20;
limit_conn_log_level notice;
 
#用戶的 IP 地址 $clientRealIP 作爲 Key,每個 IP 地址每秒處理 10 個請求
#你想用程序每秒幾百次的刷我,沒戲,再快了就不處理了,直接返回 503 錯誤給你
limit_req_zone $clientRealIP zone=ConnLimitZone:10m  rate=10r/s;
limit_req_log_level notice;

最後在Nginx的站點配置文件裏[server]模塊里加上下面一段代碼:

limit_req zone=ConnLimitZone burst=5 nodelay;

這樣限制單個真實訪客IP併發連接數以及速度限制就生效了,實現的效果是:“ 最多 5 個排隊, 由於每秒處理 10 個請求 + 5個排隊,你一秒最多發送 15 個請求過來,再多就直接返回 503 錯誤給你了

好了,今天分享這個方法,明月自己是已經在我所有的站點下都測試部署成功並生效了,上述Nginx配置代碼大家只要簡單的修改一下甚至可以直接複製粘貼就可以使用了,只是每段代碼大家要搞清楚具體放到哪裏,放錯位置可是會造成Nginx重啓失效的,所以大家每次修改了對應的conf文件後記得要nginx -t讓Nginx檢查一下配置文件是否有錯誤,以免造成服務器宕機的風險。

參考:

https://www.imydl.tech/lnmp/231.html

https://blog.csdn.net/keketrtr/article/details/75315330

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章