308 lines
7.9 KiB
Lua
308 lines
7.9 KiB
Lua
local match = string.match
|
|
local ngx_match = ngx.re.match
|
|
local unescape = ngx.unescape_uri
|
|
local get_headers = ngx.req.get_headers
|
|
|
|
function getClientIp()
|
|
IP = 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 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, tag)
|
|
if attack_log 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.."\" \""..tag.."\"\n"
|
|
else
|
|
line = realIp.." ["..time.."] \""..method.." "..servername..url.."\" \""..data.."\" - \""..tag.."\"\n"
|
|
end
|
|
local filename = logpath..'/'..servername.."_"..ngx.today().."_sec.log"
|
|
write(filename,line)
|
|
end
|
|
end
|
|
|
|
------------------------------------ 规则读取函数 -----------------------------------------
|
|
-- function readRule(var)
|
|
-- file = io.open(rule_path..'/'..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
|
|
|
|
-- url_rules = readRule('url')
|
|
-- white_url_rules = readRule('white_url')
|
|
-- args_rules = readRule('args')
|
|
-- ua_rules = readRule('user_agent')
|
|
-- post_rules = readRule('post')
|
|
-- cookie_rules = readRule('cookie')
|
|
|
|
|
|
function debugSay(msg)
|
|
if debug then
|
|
ngx.header.content_type = "text/html"
|
|
ngx.status = ngx.HTTP_FORBIDDEN
|
|
ngx.say(msg)
|
|
ngx.exit(ngx.status)
|
|
end
|
|
end
|
|
|
|
|
|
-- function whiteURLCheck()
|
|
-- if white_url_rules ~= nil then
|
|
-- for _, rule in pairs(white_url_rules) do
|
|
-- if ngx_match(ngx.var.uri, rule, "isjo") then
|
|
-- return true
|
|
-- end
|
|
-- end
|
|
-- end
|
|
-- return false
|
|
-- end
|
|
|
|
|
|
-- function fileExtCheck(ext, black_file_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
|
|
-- if attack_log then
|
|
-- log('POST',ngx.var.request_uri,"-","file attack with ext "..ext)
|
|
-- end
|
|
|
|
-- if debug then
|
|
-- debugSay(ngx.var.request_uri.."-".."file attack with ext: "..ext)
|
|
-- end
|
|
-- 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 checkArgs()
|
|
-- for _, rule in pairs(args_rules) do
|
|
-- local args = ngx.req.get_uri_args()
|
|
-- for key, val in pairs(args) do
|
|
-- if type(val) == 'table' then
|
|
-- if val ~= false then
|
|
-- data = table.concat(val, " ")
|
|
-- end
|
|
-- else
|
|
-- data = val
|
|
-- end
|
|
-- if data and type(data) ~= "boolean" and rule ~="" and ngx_match(unescape(data), rule, "isjo") then
|
|
-- log('GET', ngx.var.request_uri, "-", rule)
|
|
-- debugSay(ngx.var.request_uri.."-"..rule)
|
|
-- 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(cc_rate, cc_deny_seconds)
|
|
local uri = ngx.var.uri
|
|
cc_count = tonumber(string.match(cc_rate, '(.*)/'))
|
|
cc_seconds = tonumber(string.match(cc_rate, '/(.*)'))
|
|
local token = getClientIp()..uri
|
|
local limit = ngx.shared.limit
|
|
local req, _ = limit:get(token)
|
|
local ip = getClientIp()
|
|
local block, _ = limit:get(ip)
|
|
|
|
if block then
|
|
if debug then
|
|
ngx.say('Deny by waf.')
|
|
return false
|
|
elseif cc_redirect then
|
|
ngx.redirect(cc_redirect_url)
|
|
else
|
|
ngx.exit(404)
|
|
end
|
|
end
|
|
|
|
if req then
|
|
if req > cc_count then
|
|
limit:set(ip, 1, cc_deny_seconds)
|
|
ngx.exit(404)
|
|
return false
|
|
else
|
|
limit:incr(token, 1)
|
|
end
|
|
else
|
|
limit:set(token, 1, cc_seconds)
|
|
end
|
|
return true
|
|
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 string.split(str, delimiter)
|
|
-- if str==nil or str=='' or delimiter==nil then
|
|
-- return nil
|
|
-- end
|
|
|
|
-- local result = {}
|
|
-- for match in (str..delimiter):gmatch("(.-)"..delimiter) do
|
|
-- table.insert(result, match)
|
|
-- end
|
|
-- return result
|
|
-- end
|
|
|
|
-- function innet(ip, network)
|
|
-- local star = ''
|
|
-- for i in string.gmatch(network, '%*') do
|
|
-- star = star..i
|
|
-- end
|
|
|
|
-- local ip = string.split(ip, '%.')
|
|
-- local network = string.split(network, '%.')
|
|
-- if ip == nil or network == nil then
|
|
-- return false
|
|
-- end
|
|
|
|
-- local ip_prefix = {}
|
|
-- local network_prefix = {}
|
|
-- for i=1, 4-string.len(star) do
|
|
-- ip_prefix[i] = ip[i]
|
|
-- network_prefix[i] = network[i]
|
|
-- end
|
|
|
|
-- ip_prefix = table.concat(ip_prefix, '.')
|
|
-- network_prefix = table.concat(network_prefix, '.')
|
|
|
|
-- if ip_prefix == network_prefix then
|
|
-- return true
|
|
-- else
|
|
-- return false
|
|
-- end
|
|
-- end
|
|
|
|
-- function whiteip()
|
|
-- if next(ipWhitelist) ~= nil then
|
|
-- ip = getClientIp()
|
|
-- for _,wip in pairs(ipWhitelist) do
|
|
-- if ip == wip or innet(ip, wip) then
|
|
-- return true
|
|
-- end
|
|
-- end
|
|
-- end
|
|
-- return false
|
|
-- end
|
|
|
|
-- function blockip()
|
|
-- if next(ipBlocklist) ~= nil then
|
|
-- ip = getClientIp()
|
|
-- for _,bip in pairs(ipBlocklist) do
|
|
-- if ip == bip or ip=="0.0.0.0" or innet(ip, bip) then
|
|
-- ngx.exit(403)
|
|
-- return true
|
|
-- end
|
|
-- end
|
|
-- end
|
|
-- return false
|
|
-- end
|