使用 Nginx 實現動態封禁 IP,防止惡意爬蟲、暴力破解和 SQL 注入等攻擊,可采用兩種方案:操作系統層面的攔截(iptables)或 Web 服務器層面的攔截(Nginx + Lua)。
聊一個我最近處理的技術難題——如何用 Nginx 實現動態封禁 IP,防止一些討厭的爬蟲或者惡意用戶對你的網站進行惡意攻擊。
想必大家也遇到過那些爬蟲一遍又一遍瘋狂請求服務器,吃掉了大量的帶寬資源,或者有些惡意用戶嘗試用暴力破解方式登陸,著實讓人頭疼。
幸好,Nginx 和 Lua 結合 Redis,給我們提供了一個既高效又靈活的方案。
1. 背景與需求
有時候,你的服務器會遭遇一些惡意的攻擊,常見的就是爬蟲、暴力破解、SQL 注入,甚至 DDoS 攻擊。
這些行為不僅增加了服務器負擔,還可能導致資源浪費,甚至直接造成服務中斷。解決這些問題的一種方式就是通過 IP 封禁,尤其是對于那些惡意訪問頻繁的 IP 地址。封禁的策略應該是動態的,可以隨時添加和移除 IP,同時還要控制封禁的時長,以避免誤傷正常用戶。
我們希望通過以下幾個步驟來實現這個目標:
封禁爬蟲與惡意用戶請求:識別并封禁那些頻繁請求且行為惡意的 IP 地址。
建立動態 IP 黑名單:這個黑名單需要能動態更新,支持實時封禁。
封禁失效時間設置:封禁的 IP 不可能永遠存在黑名單中,我們需要設置一個失效時間,自動解封。
2. 方案設計
解決這個問題的方案有好幾種,每種方法都有其優缺點。
我們可以從操作系統、Web 服務器或應用層面入手,選擇適合的技術棧。下面我們分析一下每種方案。
方法 1:操作系統層面的攔截(iptables)
iptables 是 Linux 系統自帶的防火墻工具,通過它可以輕松封禁 IP。不過,這種方式的缺點是操作繁瑣且不靈活。每當需要動態封禁某個 IP 時,我們得手動去操作,不太適合自動化管理。而且,這樣的封禁是全局生效的,一旦添加了黑名單中的 IP,它就完全無法訪問服務器,除非手動移除。
方法 2:Web 服務器層面的攔截(Nginx + Lua)
這種方法是我們今天的重點,利用 Nginx 的 Lua 模塊配合 Redis,可以非常靈活地動態封禁 IP。Nginx 負責處理請求,Lua 腳本在請求到來時判斷 IP 是否需要封禁,而 Redis 則用來存儲 IP 黑名單和封禁時長。
這個方法的優點是:
動態封禁:我們可以設置一個超時機制,自動解封被封禁的 IP。
分布式管理:通過 Redis 存儲黑名單,可以在多臺服務器間共享數據,方便管理。
靈活性:可以對封禁策略進行動態調整,甚至支持高級的 IP 限制和行為監控。
缺點是:我們需要了解 Nginx 配置、Lua 腳本編寫以及 Redis 的使用。
方法 3:應用層面的攔截(代碼實現)
這種方法通過在應用層直接判斷 IP 是否在黑名單中來控制訪問。實現起來簡單直觀,但性能不如前兩者。每當一個請求到來時,代碼會去查詢黑名單,這對于高并發場景可能會帶來一定的性能壓力。
3. Nginx + Lua + Redis 方案實現
接下來,我們深入講解如何通過 Nginx 配合 Lua 腳本以及 Redis 實現動態 IP 封禁。首先,我們需要確保系統已經安裝了 Lua 和 Redis,并且 Nginx 已經配置了 Lua 模塊。
Nginx 配置
首先,在 Nginx 配置文件中,我們需要啟用 Lua 模塊,并且指定 Lua 腳本來處理訪問控制。修改 nginx.conf 配置文件,在需要處理請求的 location 塊中添加 Lua 腳本調用。
http { lua_shared_dict limit_req_zone 10m; # 用來存放 Redis 連接池 server { listen 80; location / { set $limit 0; access_by_lua_file /etc/nginx/lua/access_limit.lua; # 引用 Lua 腳本 } } }
Lua 腳本實現(access_limit.lua)
接下來我們實現 access_limit.lua 腳本,主要完成以下幾個任務:
連接 Redis。
獲取請求中的客戶端 IP 地址。
判斷該 IP 是否在黑名單中。
如果不在黑名單中,則記錄訪問次數;如果在黑名單中,則拒絕請求。
local redis = require "resty.redis" -- 引入 Redis 庫 local red = redis:new() -- 創建 Redis 對象 red:set_timeout(1000) -- 設置連接超時時間為 1 秒 -- 連接到 Redis 服務器 local ok, err = red:connect("127.0.0.1", 6379) if not ok then ngx.log(ngx.ERR, "failed to connect to Redis: ", err) return ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) end -- 獲取客戶端 IP 地址 local client_ip = ngx.var.remote_addr -- 檢查該 IP 是否在黑名單中 local res, err = red:get("blacklist:" .. client_ip) if res == "1" then ngx.log(ngx.ERR, "IP " .. client_ip .. " is blacklisted") return ngx.exit(ngx.HTTP_FORBIDDEN) end -- 如果 IP 不在黑名單中,則統計訪問次數 local visits, err = red:get("visits:" .. client_ip) if visits == ngx.null then visits = 0 end visits = visits + 1 -- 如果訪問次數超過設定閾值,則加入黑名單 if visits > 10 then -- 設定的閾值為 10 次請求 red:set("blacklist:" .. client_ip, 1) red:expire("blacklist:" .. client_ip, 3600) -- 設置封禁時長為 1 小時 end -- 更新訪問次數 red:set("visits:" .. client_ip, visits) red:expire("visits:" .. client_ip, 60) -- 設置過期時間為 1 分鐘
這個腳本通過 Redis 存儲訪問數據并動態判斷是否需要封禁 IP。如果某個 IP 在短時間內超過了訪問次數限制(比如 10 次),它就會被封禁 1 小時。
Redis 配置與連接
在這段 Lua 腳本中,我們通過 resty.redis 模塊連接 Redis 服務器。Redis 在這里充當了一個緩存的角色,用來存儲每個 IP 的訪問次數和黑名單信息。使用 Redis 的好處是它具有高性能、易于擴展且支持分布式管理。
4. 方案總結
通過 Nginx + Lua + Redis,我們可以高效地實現 IP 封禁策略。這個方案的優點在于:
配置簡單,且無需改變業務代碼。
適合高并發的場景,對性能影響較小。
支持動態配置,封禁時長可以靈活調整。
Redis 支持分布式管理,可以擴展到多臺服務器。
此外,Redis 還可以用于實現更多高級功能,例如 IP 訪問頻率限制、暴力破解防護等。
5. 擴展與高級功能
除了基本的封禁功能,Nginx + Lua + Redis 還可以擴展為更強大的安全防護系統。例如:
異常檢測與自動封禁:通過分析訪問日志,檢測異常訪問模式,自動封禁異常 IP。
白名單機制:對于一些可信的 IP,可以設置白名單,讓它們繞過封禁規則。
驗證碼驗證:對頻繁訪問的 IP 提供驗證碼驗證,進一步阻止惡意訪問。
數據統計與分析:記錄封禁的數據,通過分析日志來優化封禁策略。
總之,Nginx 與 Lua 腳本的結合,使得動態封禁 IP 成為一個簡單而靈活的解決方案,不僅能有效防止惡意訪問,還可以根據需要進行擴展與優化。
原文來源:https://mp.weixin.qq.com/s/exNdmfbyX48QoDtdVLdOtQ
來源:本文內容搜集或轉自各大網絡平臺,并已注明來源、出處,如果轉載侵犯您的版權或非授權發布,請聯系小編,我們會及時審核處理。
聲明:江蘇教育黃頁對文中觀點保持中立,對所包含內容的準確性、可靠性或者完整性不提供任何明示或暗示的保證,不對文章觀點負責,僅作分享之用,文章版權及插圖屬于原作者。
Copyright?2013-2024 JSedu114 All Rights Reserved. 江蘇教育信息綜合發布查詢平臺保留所有權利
蘇公網安備32010402000125
蘇ICP備14051488號-3技術支持:南京博盛藍睿網絡科技有限公司
南京思必達教育科技有限公司版權所有 百度統計