ngx_lua_waf/init.lua

307 lines
8.0 KiB
Lua

require 'config'
local match = string.match
local ngxmatch=ngx.re.find
local unescape=ngx.unescape_uri
local get_headers = ngx.req.get_headers
local optionIsOn = function (options) return options == "on" and true or false end
logpath = logdir
rulepath = RulePath
UrlDeny = optionIsOn(UrlDeny)
PostCheck = optionIsOn(postMatch)
CookieCheck = optionIsOn(cookieMatch)
WhiteCheck = optionIsOn(whiteModule)
PathInfoFix = optionIsOn(PathInfoFix)
attacklog = optionIsOn(attacklog)
CCDeny = optionIsOn(CCDeny)
Redirect=optionIsOn(Redirect)
function getClientIp()
IP = ngx.req.get_headers()["X-Real-IP"]
if IP == nil then
IP = ngx.var.remote_addr
end
if IP == nil then
IP = "unknown"
end
return IP
end
function getSLBIP()
IP = ngx.req.get_headers()["x_forwarded_for"]
if IP == nil then
IP = ngx.var.remote_addr
end
if IP == nil then
IP = "unknown"
end
return IP
end
function write(logfile,msg)
local fd = io.open(logfile,"ab")
if fd == nil then return end
fd:write(msg)
fd:flush()
fd:close()
end
function log(method,url,data,ruletag)
if attacklog then
local realIp = getClientIp()
local xTransIP = getSLBIP()
local ua = ngx.var.http_user_agent
local servername=ngx.var.server_name
local time=ngx.localtime()
if ua then
line = realIp.." "..xTransIP.." ["..time.."] \""..method.." "..servername..url.."\" \""..data.."\" \""..ua.."\" \""..ruletag.."\"\n"
else
line = realIp.." "..xTransIP.." ["..time.."] \""..method.." "..servername..url.."\" \""..data.."\" - \""..ruletag.."\"\n"
end
local filename = logpath..'/'..servername.."_"..ngx.today().."_sec.log"
write(filename,line)
end
end
------------------------------------规则读取函数-------------------------------------------------------------------
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
urlrules=read_rule('url')
argsrules=read_rule('args')
uarules=read_rule('user-agent')
wturlrules=read_rule('whiteurl')
postrules=read_rule('post')
ckrules=read_rule('cookie')
function getWhiteList()
return read_rule("ipwhitelist")
end
function getBlackList()
return read_rule("ipblacklist")
end
function say_html()
if Redirect then
ngx.header.content_type = "text/html"
ngx.status = ngx.HTTP_FORBIDDEN
ngx.say(html)
ngx.exit(ngx.status)
end
end
function say_html_503()
if Redirect then
ngx.header.content_type = "text/html"
ngx.status = ngx.HTTP_SERVICE_UNAVAILABLE
ngx.say(html503)
ngx.exit(ngx.status)
end
end
function 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 false
end
function 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 false
end
function Set (list)
local set = {}
for _, l in ipairs(list) do set[l] = true end
return set
end
function 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
data=table.concat(val, " ")
else
data=val
end
if data and type(data) ~= "boolean" and rule ~="" and ngxmatch(unescape(data),rule,"ijos") then
log('GET',ngx.var.request_uri,"-",rule)
say_html()
return true
end
end
end
return false
end
function 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 false
end
function 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 false
end
function 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 false
end
function 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 false
end
function denycc()
if CCDeny then
-- Yep, use wafconfig
ccconf = read_rule("ccrate")
if next(ccconf) ~= nil then
for _, conf in pairs(ccconf) do
CCrate = conf
conf = nil
break
end
end
ccconf = nil
-- Done
local uri=ngx.var.uri
CCcount=tonumber(string.match(CCrate,'(.*)/'))
CCseconds=tonumber(string.match(CCrate,'/(.*)'))
local token = getClientIp()..uri
local limit = ngx.shared.limit
local req,_=limit:get(token)
if req then
if req > CCcount then
-- ngx.say(html503)
-- ngx.exit(503)
log('CC',ngx.var.request_uri,"-","We are under attack!")
say_html_503()
return true
else
limit:incr(token,1)
end
else
limit:set(token,1,CCseconds)
end
end
return false
end
function 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=([^\",;]+)")
end
function whiteip()
ipWhitelist = getWhiteList()
if next(ipWhitelist) ~= nil then
for _,ip in pairs(ipWhitelist) do
if getClientIp()==ip then
return true
end
end
end
return false
end
function blockip()
ipBlocklist = getBlackList()
if next(ipBlocklist) ~= nil then
for _,ip in pairs(ipBlocklist) do
if getClientIp()==ip then
if path403 == nil then
path403 = "403"
end
if string.match(ngx.var.request_uri, '/(.*)') ~= path403 then
p = string.match(ngx.var.request_uri, '/([a-zA-Z0-9]*)')
if next(uriWhitelist) ~= nil and p ~= nil then
deny = true
for _,uri in pairs(uriWhitelist) do
if ngx.re.match(p,uri,"isjo") then
deny = false
break
end
end
if deny == true then
log('DENY',ngx.var.request_uri,"-","GO HELL!")
say_html()
end
return true
end
end
return true
end
end
end
return false
end