宝塔面板Nginx的Lua-Waf防火墙终极改进 动态封禁IP
![]() | ![]() | ![]() | ![]() |
| 【性价之王】 | 【线路之王】 | 【价格之王】 | 【配置之王】 |
| 【免费之王】 | 【香港首推】 | 【梯子之王】 | 【独服之王】 |

宝塔面板自带的Nginx防火墙有些鸡肋,对于大量的恶意攻击只能临时拦截,而不能封禁IP。
延伸阅读:Oneinstack一键开启安装ngx_lua_waf防火墙功能
下面的修改可以帮你做到,频繁CC攻击,频繁的漏洞扫描,同一个IP段轮流攻击,使用了CDN进行攻击,都可以全部封禁。
宝塔面板的nginx修改/www/server/nginx/waf/目录下的三个文件即可,如果没有宝塔面板,nginx必须安装Lua,然后对下面的代码稍加修改,并且自己加上正则黑名单(或者下载个宝塔面板把规则文件拷出来)也可以正常使用。
代码:config.lua
RulePath = "/www/server/panel/vhost/wafconf/" --规则文件夹attacklog="on"logdir = "/www/wwwlogs/waf/" --日志文件夹UrlDeny="on"Redirect="on"CookieMatch="on"postMatch="on"whiteModule="on" black_fileExt={"php"}ipWhitelist={}ipBlocklist={}CCDeny="on"CCrate="500/100" --这个是CC攻击的几秒钟允许请求几次代码:init.lua
require 'config'local match = string.matchlocal ngxmatch=ngx.re.findlocal unescape=ngx.unescape_urilocal get_headers = ngx.req.get_headerslocal optionIsOn = function (options) return options == "on" and true or false endlogpath = logdir rulepath = RulePathUrlDeny = optionIsOn(UrlDeny)PostCheck = optionIsOn(postMatch)CookieCheck = optionIsOn(cookieMatch)WhiteCheck = optionIsOn(whiteModule)PathInfoFix = optionIsOn(PathInfoFix)attacklog = optionIsOn(attacklog)CCDeny = optionIsOn(CCDeny)Redirect=optionIsOn(Redirect)function subString(str, k) --截取字符串 ts = string.reverse(str) _, i = string.find(ts, k) m = string.len(ts) - i + 1 return string.sub(str, 1, m)endfunction getClientIp() IP = ngx.var.remote_addr if ngx.var.HTTP_X_FORWARDED_FOR then IP = ngx.var.HTTP_X_FORWARDED_FOR end if IP == nil then IP = "unknown" end IP = subString(IP, "[.]") .. "*" return IPendfunction getRealIp() IP = ngx.var.remote_addr if ngx.var.HTTP_X_FORWARDED_FOR then --如果用了CDN,判断真实IP IP = ngx.var.HTTP_X_FORWARDED_FOR end if IP == nil then IP = "unknown" end return IPendfunction write(logfile,msg) local fd = io.open(logfile,"ab") if fd == nil then return end fd:write(msg) fd:flush() fd:close()endfunction log(method,url,data,ruletag) if attacklog then local realIp = getRealIp() local ua = ngx.var.http_user_agent local servername=ngx.var.server_name local time=ngx.localtime() if ua then line = realIp.." ["..time.."] \""..method.." "..servername..url.."\" \""..data.."\" \""..ua.."\" \""..ruletag.."\"\n" else line = realIp.." ["..time.."] \""..method.." "..servername..url.."\" \""..data.."\" - \""..ruletag.."\"\n" end local filename = logpath..'/'..servername.."_"..ngx.today().."_sec.log" write(filename,line) endend------------------------------------规则读取函数-------------------------------------------------------------------function read_rule(var) file = io.open(rulepath..'/'..var,"r") if file==nil then return end t = {} for line in file:lines() do table.insert(t,line) end file:close() return(t)end-----------------------------------频繁扫描封禁ip-------------------------------------------------------------------function ban_ip(point) local token = getClientIp() .. "_WAF" local limit = ngx.shared.limit local req,_=limit:get(token) if req then limit:set(token,req+point,3600) --发现一次,增加积分,1小时内有效 else limit:set(token,point,3600) endendfunction get_ban_times() local token = getClientIp() .. "_WAF" local limit = ngx.shared.limit local req,_=limit:get(token) if req then return req else return 0 endendfunction is_ban() local ban_times = get_ban_times() if ban_times >= 100 then --超过100积分,ban ngx.header.content_type = "text/html;charset=UTF-8" ngx.status = ngx.HTTP_FORBIDDEN ngx.exit(ngx.status) return true else return false end return falseendurlrules=read_rule('url')argsrules=read_rule('args')uarules=read_rule('user-agent')wturlrules=read_rule('whiteurl')postrules=read_rule('post')ckrules=read_rule('cookie')html=read_rule('returnhtml')function say_html() ban_ip(15) --恶意攻击,罚15分 if Redirect then ngx.header.content_type = "text/html;charset=UTF-8" ngx.status = ngx.HTTP_FORBIDDEN ngx.say(html) ngx.exit(ngx.status) endendfunction whiteurl() if WhiteCheck then if wturlrules ~=nil then for _,rule in pairs(wturlrules) do if ngxmatch(ngx.var.uri,rule,"isjo") then return true end end end end return falseendfunction fileExtCheck(ext) local items = Set(black_fileExt) ext=string.lower(ext) if ext then for rule in pairs(items) do if ngx.re.match(ext,rule,"isjo") then log('POST',ngx.var.request_uri,"-","file attack with ext "..ext) say_html() end end end return falseendfunction Set (list) local set = {} for _, l in ipairs(list) do set[l] = true end return setendfunction args() for _,rule in pairs(argsrules) do local args = ngx.req.get_uri_args() for key, val in pairs(args) do if type(val)=='table' then local t={} for k,v in pairs(val) do if v == true then v="" end table.insert(t,v) end data=table.concat(t, " ") else data=val end if data and type(data) ~= "boolean" and rule ~="" and ngxmatch(unescape(data),rule,"isjo") then log('GET',ngx.var.request_uri,"-",rule) say_html() return true end end end return falseendfunction url() if UrlDeny then for _,rule in pairs(urlrules) do if rule ~="" and ngxmatch(ngx.var.request_uri,rule,"isjo") then log('GET',ngx.var.request_uri,"-",rule) say_html() return true end end end return falseendfunction ua() local ua = ngx.var.http_user_agent if ua ~= nil then for _,rule in pairs(uarules) do if rule ~="" and ngxmatch(ua,rule,"isjo") then log('UA',ngx.var.request_uri,"-",rule) say_html() return true end end end return falseendfunction body(data) for _,rule in pairs(postrules) do if rule ~="" and data~="" and ngxmatch(unescape(data),rule,"isjo") then log('POST',ngx.var.request_uri,data,rule) say_html() return true end end return falseendfunction cookie() local ck = ngx.var.http_cookie if CookieCheck and ck then for _,rule in pairs(ckrules) do if rule ~="" and ngxmatch(ck,rule,"isjo") then log('Cookie',ngx.var.request_uri,"-",rule) say_html() return true end end end return falseendfunction denycc() if CCDeny then CCcount=tonumber(string.match(CCrate,'(.*)/')) CCseconds=tonumber(string.match(CCrate,'/(.*)')) local token = getRealIp() local limit = ngx.shared.limit local req,_=limit:get(token) if req then if req > CCcount then limit:incr(token,1) ban_ip(req - CCcount) --CC攻击,罚分 ngx.header.content_type = "text/html" ngx.status = ngx.HTTP_FORBIDDEN ngx.say("老哥你手速也忒快了吧,要不休息"..CCcount.."秒?") ngx.exit(ngx.status) return true else limit:incr(token,1) end else limit:set(token,1,CCseconds) end end return falseendfunction get_boundary() local header = get_headers()["content-type"] if not header then return nil end if type(header) == "table" then header = header[1] end local m = match(header, ";%s*boundary=\"([^\"]+)\"") if m then return m end return match(header, ";%s*boundary=([^\",;]+)")endfunction whiteip() if next(ipWhitelist) ~= nil then for _,ip in pairs(ipWhitelist) do if getClientIp()==ip then return true end end end return falseendfunction blockip() if next(ipBlocklist) ~= nil then for _,ip in pairs(ipBlocklist) do if getClientIp()==ip then ngx.exit(444) return true end end end return falseend代码:waf.lua
local content_length=tonumber(ngx.req.get_headers()['content-length'])local method=ngx.req.get_method()local ngxmatch=ngx.re.matchif whiteip() thenelseif blockip() thenelseif whiteurl() thenelseif is_ban() thenelseif denycc() thenelseif ngx.var.http_Acunetix_Aspect then ngx.exit(444)elseif ngx.var.http_X_Scan_Memo then ngx.exit(444)elseif ua() thenelseif url() thenelseif args() thenelseif cookie() thenelseif PostCheck then if method=="POST" then local boundary = get_boundary() if boundary then local len = string.len local sock, err = ngx.req.socket() if not sock then return end ngx.req.init_body(128 * 1024) sock:settimeout(0) local content_length = nil content_length=tonumber(ngx.req.get_headers()['content-length']) local chunk_size = 4096 if content_length < chunk_size then chunk_size = content_length end local size = 0 while size < content_length do local data, err, partial = sock:receive(chunk_size) data = data or partial if not data then return end ngx.req.append_body(data) if body(data) then return true end size = size + len(data) local m = ngxmatch(data,[[Content-Disposition: form-data;(.+)filename="(.+)\\.(.*)"]],'ijo') if m then fileExtCheck(m[3]) filetranslate = true else if ngxmatch(data,"Content-Disposition:",'isjo') then filetranslate = false end if filetranslate==false then if body(data) then return true end end end local less = content_length - size if less < chunk_size then chunk_size = less end end ngx.req.finish_body() else ngx.req.read_body() local args = ngx.req.get_post_args() if not args then return end for key, val in pairs(args) do if type(val) == "table" then if type(val[1]) == "boolean" then return end data=table.concat(val, ", ") else data=val end if data and type(data) ~= "boolean" and body(data) then body(key) end end end endelse returnend[Lua-Waf防火墙]历史优惠活动内容
猜你可能想看的VPS
- phpStudy 报 SMTP Error: Could not con全球[VPS测评]
- php 截取字符串函数全球[VPS测评]
- 阿里云采购节云服务器选购攻略 国内香港免备案 89 元每年起香港VPS[主机]
- Gumlet→图片加速 CDN AWS 亚洲节点 免费 1GB 月流量;全球[VPS测评]
- 企鹅小屋→600 元 季 2*L56XX 8GB 内存 1TB 硬盘 不香港VPS[主机]
- 景文互联→VPS 全场 7 折 年付内存翻倍 充值 1000 元送 30全球[VPS测评]
- 搬瓦工 香港 pccw 机器 39.99 刀的已经下架 目前 79.99香港VPS[主机]
- Sharedspace→$4 月 1GB 内存 20GB SSD 空间 虚拟空间(主机)
- gigsgigscloud→洛杉矶 CN2 GIA $4.99 月 低配全球[VPS测评]
- OVHcloud→$3.5 月 2GB 内存 20GB NVMe SSD虚拟空间(主机)
- ONEVPS→$4 月 KVM-512MB 20G SSD 1G 无限流日本VPS[主机]
- ZJI - 春节促销全场八折 香港云地四型独服买 2 月送 1 月香港VPS[主机]
- HostKvm 双节促销 全场8折 新上架韩国VPS plan2/Pla韩国VPS[主机]
- EtherNetservers促销套餐 1G内存/30G硬盘/2个IP 全球[VPS测评]
- 又有美议员窜访台,中国驻美大使馆:“中方将对美国的挑衅采取果断的反制措施美国VPS[主机]
- 跨境电商洋码头生死攸关:买手流失资金被冻结保全全球[VPS测评]
- 磐逸云怎么样?香港沙田cn2vps 带宽5M年付128元香港VPS[主机]
- YYYHost:4核4G香港cn2vps,20G SSD/3Mbps不限香港VPS[主机]
- RAKsmart:1核1GB/40GB空间/不限流量/15Mbps/KV虚拟空间(主机)
- 宝塔面板在香港服务器安装启动不了nginx怎么办?香港VPS[主机]
- 瓜云互联怎么样?香港/美国洛杉矶CN2高防vps 50G月付34元美国VPS[主机]
- 快速云:科普云服务器服务器的概念和作用2022-08-2313:26来源全球[VPS测评]
- UOVZ怎么样?香港30M大带宽VPS 直连线路月付50元香港VPS[主机]
- 葫芦云:香港将军澳CN2云服务器24元/月,1核/1GB/25G硬盘/3香港VPS[主机]
- gcorelabs:KVM主机€1.08/月起;俄罗斯/美国/香港/日本日本VPS[主机]
- edgenat:香港vps、韩国vps、洛杉矶vps买1送1,买多久送多韩国VPS[主机]
- 雷盾云:香港/美国/日本免备案云服务器,香港vps低至10元/月日本VPS[主机]
- 阳帝云:香港大宽带vps仅15元/月;美国vps200G防御仅28元/月美国VPS[主机]
- 亿速云服务器双12活动:香港云服务器29元/月起,100GCDN流量只需香港VPS[主机]
- 拼多多拟建跨境电商平台:挖角SHEIN员工,0佣金招商入驻全球[VPS测评]
转载请注明原文地址:http://140.238.13.167:12355/read-226621.html











