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