update
This commit is contained in:
parent
5a52ed41ad
commit
34f8ef702d
|
|
@ -135,10 +135,14 @@ def stop():
|
|||
|
||||
|
||||
def restart():
|
||||
stop()
|
||||
start()
|
||||
return 'ok'
|
||||
|
||||
|
||||
def reload():
|
||||
stop()
|
||||
start()
|
||||
return 'ok'
|
||||
|
||||
def getJsonPath(name):
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
|
||||
|
||||
function return_message(status,msg)
|
||||
ngx.header.content_type = "application/json;"
|
||||
ngx.status = status
|
||||
ngx.say(json.encode(msg))
|
||||
ngx.exit(status)
|
||||
end
|
||||
|
||||
|
||||
function return_html(status,html)
|
||||
ngx.header.content_type = "text/html"
|
||||
ngx.status = status
|
||||
ngx.say(html)
|
||||
ngx.exit(status)
|
||||
end
|
||||
|
||||
function read_file_body(filename)
|
||||
fp = io.open(filename,'r')
|
||||
if fp == nil then
|
||||
return nil
|
||||
end
|
||||
fbody = fp:read("*a")
|
||||
fp:close()
|
||||
if fbody == '' then
|
||||
return nil
|
||||
end
|
||||
return fbody
|
||||
end
|
||||
|
||||
|
|
@ -1,261 +1,52 @@
|
|||
RulePath = "{$WAF_PATH}/wafconf"
|
||||
attacklog = "on"
|
||||
logdir = "{$ROOT_PATH}/wwwlogs/waf/"
|
||||
UrlDeny="on"
|
||||
Redirect="on"
|
||||
CookieMatch="off"
|
||||
postMatch="off"
|
||||
whiteModule="on"
|
||||
black_fileExt={"php","jsp"}
|
||||
ipWhitelist={"127.0.0.2"}
|
||||
ipBlocklist={"1.0.0.1"}
|
||||
CCDeny="off"
|
||||
CCrate="300/60"
|
||||
local cpath = "{$WAF_PATH}/"
|
||||
local logdir = "{$ROOT_PATH}/wwwlogs/waf/"
|
||||
local json = require "cjson"
|
||||
|
||||
|
||||
|
||||
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.var.remote_addr
|
||||
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 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)
|
||||
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')
|
||||
html=read_rule('returnhtml')
|
||||
|
||||
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 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
|
||||
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 false
|
||||
function return_message(status,msg)
|
||||
ngx.header.content_type = "application/json;"
|
||||
ngx.status = status
|
||||
ngx.say(json.encode(msg))
|
||||
ngx.exit(status)
|
||||
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
|
||||
function return_html(status,html)
|
||||
ngx.header.content_type = "text/html"
|
||||
ngx.status = status
|
||||
ngx.say(html)
|
||||
ngx.exit(status)
|
||||
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
|
||||
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.exit(444)
|
||||
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
|
||||
function read_file_body(filename)
|
||||
fp = io.open(filename,'r')
|
||||
if fp == nil then
|
||||
return nil
|
||||
end
|
||||
|
||||
if type(header) == "table" then
|
||||
header = header[1]
|
||||
fbody = fp:read("*a")
|
||||
fp:close()
|
||||
if fbody == '' then
|
||||
return nil
|
||||
end
|
||||
|
||||
local m = match(header, ";%s*boundary=\"([^\"]+)\"")
|
||||
if m then
|
||||
return m
|
||||
end
|
||||
|
||||
return match(header, ";%s*boundary=([^\",;]+)")
|
||||
return fbody
|
||||
end
|
||||
|
||||
function whiteip()
|
||||
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()
|
||||
if next(ipBlocklist) ~= nil then
|
||||
for _,ip in pairs(ipBlocklist) do
|
||||
if getClientIp()==ip then
|
||||
ngx.exit(444)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
-- local config = read_file_body(cpath .. 'config.json')
|
||||
local config = json.decode(read_file_body(cpath .. 'config.json'))
|
||||
-- local site_config = json.decode(read_file_body(cpath .. 'site.json'))
|
||||
|
||||
|
||||
-- function args()
|
||||
-- if not config['get']['open'] or not is_site_config('get') then return false end
|
||||
-- if is_ngx_match(args_rules,uri_request_args,'args') then
|
||||
-- write_log('args','regular')
|
||||
-- return_html(config['get']['status'],get_html)
|
||||
-- return true
|
||||
-- end
|
||||
-- return false
|
||||
-- end
|
||||
|
||||
function waf()
|
||||
-- return_html(200,cpath .. 'config.json')
|
||||
return_message(200, config)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,88 +1 @@
|
|||
local content_length=tonumber(ngx.req.get_headers()['content-length'])
|
||||
local method=ngx.req.get_method()
|
||||
local ngxmatch=ngx.re.match
|
||||
if whiteip() then
|
||||
elseif blockip() then
|
||||
elseif denycc() then
|
||||
elseif ngx.var.http_Acunetix_Aspect then
|
||||
ngx.exit(444)
|
||||
elseif ngx.var.http_X_Scan_Memo then
|
||||
ngx.exit(444)
|
||||
elseif whiteurl() then
|
||||
elseif ua() then
|
||||
elseif url() then
|
||||
elseif args() then
|
||||
elseif cookie() then
|
||||
elseif 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
|
||||
end
|
||||
else
|
||||
return
|
||||
end
|
||||
waf()
|
||||
Loading…
Reference in New Issue