Nginx結(jié)合Openresty通過Lua+Redis實(shí)現(xiàn)動態(tài)封禁IP
需求
為了封禁某些爬蟲或者惡意用戶對服務(wù)器的請求,我們需要建立一個動態(tài)的 IP 黑名單。對于黑名單中的 IP ,我們將拒絕提供服務(wù)。并且可以設(shè)置封禁失效時間
環(huán)境準(zhǔn)備
- linux version: centos7 / ubuntu 等
- redis version: 5.0.5
- nginx version: nginx-openresty
設(shè)計(jì)方案
實(shí)現(xiàn) IP 黑名單的功能有很多途徑:
1、在操作系統(tǒng)層面,配置 iptables,來攔截指定 IP 的網(wǎng)絡(luò)請求。
- 優(yōu)點(diǎn):簡單直接,在服務(wù)器物理層面上進(jìn)行攔截
- 缺點(diǎn):每次需要手動上服務(wù)器修改配置文件,操作繁瑣且不靈活
2、在 Web 服務(wù)器層面,通過 Nginx 自身的 deny 選項(xiàng)或者 lua 插件配置 IP 黑名單。
- 優(yōu)點(diǎn):可動態(tài)實(shí)現(xiàn)封禁 ip,通過設(shè)置封禁時間可以做到分布式封禁
- 缺點(diǎn):需要了解 Lua 腳本和 Nginx 配置,有一定的學(xué)習(xí)成本
3、在應(yīng)用層面,在處理請求之前檢查客戶端的 IP 地址是否在黑名單中。
- 優(yōu)點(diǎn):通過編寫代碼來實(shí)現(xiàn),相對簡單且易于維護(hù)。
- 缺點(diǎn):代碼可能會變得冗長,而且在高并發(fā)情況下可能影響性能。
為了方便管理和共享黑名單,通過 nginx + lua + redis 的架構(gòu)實(shí)現(xiàn) IP 黑名單的功能

配置 nginx.conf
在需要進(jìn)行限制的 server 的 location 中添加如下配置:
location / {
# 如果該location 下存在靜態(tài)資源文件可以做一個判斷
#if ($request_uri ~ .*\.(html|htm|jpg|js|css)) {
# access_by_lua_file /usr/local/lua/access_limit.lua;
#}
access_by_lua_file /usr/local/lua/access_limit.lua; # 加上了這條配置,則會根據(jù) access_limit.lua 的規(guī)則進(jìn)行限流
alias /usr/local/web/;
index index.html index.htm;
}
配置 lua 腳本
/usr/local/lua/access_limit.lua
-- 可以實(shí)現(xiàn)自動將訪問頻次過高的IP地址加入黑名單封禁一段時間
--連接池超時回收毫秒
local pool_max_idle_time = 10000
--連接池大小
local pool_size = 100
--redis 連接超時時間
local redis_connection_timeout = 100
--redis host
local redis_host = "your redis host ip"
--redis port
local redis_port = "your redis port"
--redis auth
local redis_auth = "your redis authpassword";
--封禁IP時間(秒)
local ip_block_time= 120
--指定ip訪問頻率時間段(秒)
local ip_time_out = 1
--指定ip訪問頻率計(jì)數(shù)最大值(次)
local ip_max_count = 3
-- 錯誤日志記錄
local function errlog(msg, ex)
ngx.log(ngx.ERR, msg, ex)
end
-- 釋放連接池
local function close_redis(red)
if not red then
return
end
local ok, err = red:set_keepalive(pool_max_idle_time, pool_size)
if not ok then
ngx.say("redis connct err:",err)
return red:close()
end
end
--連接redis
local redis = require "resty.redis"
local client = redis:new()
local ok, err = client:connect(redis_host, redis_port)
-- 連接失敗返回服務(wù)器錯誤
if not ok then
close_redis(client)
ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
end
--設(shè)置超時時間
client:set_timeout(redis_connection_timeout)
-- 優(yōu)化驗(yàn)證密碼操作 代表連接在連接池使用的次數(shù),如果為0代表未使用,不為0代表復(fù)用 在只有為0時才進(jìn)行密碼校驗(yàn)
local connCount, err = client:get_reused_times()
-- 新建連接,需要認(rèn)證密碼
if 0 == connCount then
local ok, err = client:auth(redis_auth)
if not ok then
errlog("failed to auth: ", err)
return
end
--從連接池中獲取連接,無需再次認(rèn)證密碼
elseif err then
errlog("failed to get reused times: ", err)
return
end
-- 獲取請求ip
local function getIp()
local clientIP = ngx.req.get_headers()["X-Real-IP"]
if clientIP == nil then
clientIP = ngx.req.get_headers()["x_forwarded_for"]
end
if clientIP == nil then
clientIP = ngx.var.remote_addr
end
return clientIP
end
local cliendIp = getIp();
local incrKey = "limit:count:"..cliendIp
local blockKey = "limit:block:"..cliendIp
--查詢ip是否被禁止訪問,如果存在則返回403錯誤代碼
local is_block,err = client:get(blockKey)
if tonumber(is_block) == 1 then
ngx.exit(ngx.HTTP_FORBIDDEN)
close_redis(client)
end
local ip_count, err = client:incr(incrKey)
if tonumber(ip_count) == 1 then
client:expire(incrKey,ip_time_out)
end
--如果超過單位時間限制的訪問次數(shù),則添加限制訪問標(biāo)識,限制時間為ip_block_time
if tonumber(ip_count) > tonumber(ip_max_count) then
client:set(blockKey,1)
client:expire(blockKey,ip_block_time)
end
close_redis(client)
總結(jié)
以上,便是 Nginx+Lua+Redis 實(shí)現(xiàn)的 IP 黑名單功能,具有如下優(yōu)點(diǎn):
- 配置簡單輕量,對服務(wù)器性能影響小。
- 多臺服務(wù)器可以通過共享 Redis 實(shí)例共享黑名單。
- 動態(tài)配置,可以手工或者通過某種自動化的方式設(shè)置 Redis 中的黑名單
擴(kuò)展
1、IP 黑名單的應(yīng)用場景
IP 黑名單在實(shí)際應(yīng)用中具有廣泛的應(yīng)用場景,主要用于保護(hù)服務(wù)器和應(yīng)用免受惡意攻擊、爬蟲或?yàn)E用行為的影響。下面列舉幾個常見的應(yīng)用場景:
- 防止惡意訪問:黑名單可以阻止那些試圖通過暴力破解密碼、SQL 注入、XSS 攻擊等方式進(jìn)行非法訪問的 IP 地址。
- 防止爬蟲和數(shù)據(jù)濫用:黑名單可以限制那些頻繁訪問網(wǎng)站并抓取大量數(shù)據(jù)的爬蟲,以減輕服務(wù)器負(fù)載和保護(hù)數(shù)據(jù)安全。
- 防止 DDOS 攻擊:黑名單可以封禁那些發(fā)起大規(guī)模DDoS攻擊的IP地址,保護(hù)服務(wù)器的穩(wěn)定性和安全性。
- 限制訪問頻率:黑名單可以限制某個IP在特定時間段內(nèi)的訪問次數(shù),防止惡意用戶進(jìn)行暴力破解、刷票等行為。
2、高級功能和改進(jìn)
除了基本的 IP 黑名單功能外,還可以進(jìn)行一些高級功能和改進(jìn),以提升安全性和用戶體驗(yàn):
- 異常檢測和自動封禁:通過分析訪問日志和行為模式,可以實(shí)現(xiàn)異常檢測功能,并自動將異常行為的 IP 地址封禁,提高安全性。
- 白名單機(jī)制:除了黑名單,還可以引入白名單機(jī)制,允許某些 IP 地址繞過黑名單限制,確保合法用戶的正常訪問。
- 驗(yàn)證碼驗(yàn)證:對于頻繁訪問或異常行為的 IP,可以要求其進(jìn)行驗(yàn)證碼驗(yàn)證,以進(jìn)一步防止惡意行為。
- 數(shù)據(jù)統(tǒng)計(jì)和分析:將黑名單相關(guān)的數(shù)據(jù)進(jìn)行統(tǒng)計(jì)和分析,例如記錄封禁 IP 的次數(shù)、持續(xù)時間等信息,以便后續(xù)優(yōu)化和調(diào)整策略。
通過不斷改進(jìn)和優(yōu)化 IP 黑名單功能,可以更好地保護(hù)服務(wù)器和應(yīng)用的安全。
到此這篇關(guān)于Nginx結(jié)合Openresty通過Lua+Redis實(shí)現(xiàn)動態(tài)封禁IP的文章就介紹到這了,更多相關(guān)Nginx 動態(tài)封禁IP內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
nginx 老網(wǎng)站域名重定向到新網(wǎng)站的方法(親測)
本文主要介紹了nginx 老網(wǎng)站域名重定向到新網(wǎng)站的方法,以減少業(yè)務(wù)影響并確保流量導(dǎo)向新域名,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2025-02-02
Nginx配置防盜鏈保護(hù)靜態(tài)資源的詳細(xì)教程
防盜鏈?zhǔn)且环N通過檢查 HTTP 請求頭中的 Referer 字段來限制資源訪問的技術(shù),常用于保護(hù)圖片、視頻等靜態(tài)資源不被其他網(wǎng)站直接引用,以下是Nginx防盜鏈的原理、配置步驟以及測試方法,幫助你快速配置和驗(yàn)證防盜鏈功能,需要的朋友可以參考下2025-02-02
Nginx部署SpringBoot項(xiàng)目的實(shí)現(xiàn)
本文主要介紹了Nginx部署SpringBoot項(xiàng)目的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-03-03
nginx和Apache配置SSL證書的實(shí)現(xiàn)步驟
SSL證書是一種數(shù)字證書,用于加密在網(wǎng)絡(luò)上發(fā)送的數(shù)據(jù)并保護(hù)敏感信息的安全性,本文主要介紹了nginx和Apache配置SSL證書的實(shí)現(xiàn)步驟,具有一定的參考價值,感興趣的可以了解一下2023-12-12
詳解nginx 代理多個服務(wù)器(多個server方式)
本篇文章主要介紹了詳解nginx 代理多個服務(wù)器(多個server方式),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-10-10
nginx 配置虛擬主機(jī),實(shí)現(xiàn)在一個服務(wù)器可以訪問多個網(wǎng)站的方法
下面小編就為大家分享一篇nginx 配置虛擬主機(jī),實(shí)現(xiàn)在一個服務(wù)器可以訪問多個網(wǎng)站的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2017-12-12

