1Panel/plugins/openresty/waf/log_and_traffic.lua

233 lines
7.2 KiB
Lua
Raw Normal View History

2024-02-28 06:34:09 +00:00
local utils = require "utils"
local stringutf8 = require "stringutf8"
local logger_factory = require "logger_factory"
local db = require "db"
local config = require "config"
local redis_util = require "redis_util"
local action = require "action"
local upper_str = string.upper
local concat_table = table.concat
local tonumber = tonumber
local get_expire_time = utils.get_expire_time
local get_date_hour = utils.get_date_hour
local get_today = ngx.today
local ATTACK_PREFIX = "attack_"
local ATTACK_TYPE_PREFIX = "attack_type_"
local function writeAttackLog()
local rule_table = ngx.ctx.rule_table
local data = ngx.ctx.hitData
local action = ngx.ctx.action
local rule = rule_table.rule
local rule_type = rule_table.type
if not rule_type then
rule_type = "default"
end
local realIp = ngx.ctx.ip
local geoip = ngx.ctx.geoip
local country = geoip.country["zh"] or ""
local province = geoip.province["zh"] or ""
local city = ""
local longitude = geoip.longitude
local latitude = geoip.latitude
local method = ngx.req.get_method()
local uri = ngx.var.request_uri
local ua = ngx.ctx.ua
local host = ngx.var.server_name
local protocol = ngx.var.server_protocol
local attackTime = ngx.localtime()
local website_key = ngx.ctx.website_key
local address = country .. province .. city
address = stringutf8.default_if_blank(address, '-')
ua = stringutf8.default_if_blank(ua, '-')
data = stringutf8.default_if_blank(data, '-')
local log_path = "/www/sites/" .. website_key .. "/attack.log"
local logStr = concat_table({ rule_type, realIp, address, "[" .. attackTime .. "]", '"' .. method, host, uri, protocol .. '"', data, '"' .. ua .. '"', '"' .. rule .. '"', action }, ' ')
local host_logger = logger_factory.get_logger(log_path, host, true)
host_logger:log(logStr .. '\n')
db.init_db()
if wafdb == nil then
return false
end
local isBlock = 0
local blocking_time = 0
if ngx.ctx.ipBlocked then
isBlock = 1
blocking_time = tonumber(rule_table.ipBlockTime)
end
local insertQuery = [[
INSERT INTO attack_log (
ip, ip_city, ip_country, ip_subdivisions, ip_continent,
ip_longitude, ip_latitude, time, localtime, server_name,
website_key, host, method, uri, user_agent, rule,
nginx_log, blocking_time, action, msg, params, is_block
) VALUES (
:realIp, :city, :country, :subdivisions, :continent,
:longitude, :latitude, :time, :localtime, :host,
:website_key, :host, :method, :uri, :ua, :rule_type,
:logStr, :blocking_time, :action, :msg, :params, :is_block
)
]]
local stmt = wafdb:prepare(insertQuery)
stmt:bind_names {
realIp = realIp,
city = city,
country = country,
subdivisions = "",
continent = "",
longitude = longitude,
latitude = latitude,
time = os.time(),
localtime = os.date("%Y-%m-%d %H:%M:%S", os.time()),
host = host,
website_key = website_key,
method = method,
uri = uri,
ua = ua,
rule_type = rule_type,
logStr = logStr,
blocking_time = blocking_time or 0,
action = action,
msg = "msg",
params = "Params",
is_block = isBlock
}
local code = stmt:step()
stmt:finalize()
if code ~= 101 then
local errorMsg = wafdb:errmsg()
if errorMsg then
ngx.log(ngx.ERR, "insert attack_log error", errorMsg)
end
end
end
local function writeIPBlockLog()
local rule_table = ngx.ctx.rule_table
local ip = ngx.ctx.ip
local website_key = ngx.ctx.website_key
local log_path = "/www/sites/" .. website_key .. "/attack.log"
local host_logger = logger_factory.get_logger(log_path .. "ipBlock.log", 'ipBlock', false)
host_logger:log(concat_table({ ngx.localtime(), ip, rule_table.type, rule_table.ipBlockTime .. 's' }, ' ') .. "\n")
--todo 永久拉黑IP
--if rule_table.ipBlockTimeout == 0 then
-- local ipBlackLogger = logger_factory.get_logger(rulePath .. "ipBlackList", 'ipBlack', false)
-- ipBlackLogger:log(ip .. "\n")
--end
end
-- 按小时统计当天请求流量存入缓存key格式2023-05-05 09
local function countRequestTraffic()
local hour = get_date_hour()
local dict = ngx.shared.dict_req_count
local expire_time = get_expire_time()
local count, err = dict:incr(hour, 1, 0, expire_time)
if not count then
dict:set(hour, 1, expire_time)
ngx.log(ngx.ERR, "failed to count traffic ", err)
end
end
--[[
keyattack_2023-05-05 09
keyattack_type_2023-05-05_ARGS
]]
local function countAttackRequestTraffic()
local rule_table = ngx.ctx.rule_table
local rule_type = ""
if rule_table.rule_type then
rule_type = upper_str(rule_table.rule_type)
end
if rule_table.type then
rule_type = upper_str(rule_table.type)
end
local dict = ngx.shared.dict_req_count
local count, err = nil, nil
local expire_time = get_expire_time()
if rule_type ~= 'WHITEIP' then
local hour = get_date_hour()
local key = ATTACK_PREFIX .. hour
count, err = dict:incr(key, 1, 0, expire_time)
if not count then
dict:set(key, 1, expire_time)
ngx.log(ngx.ERR, "failed to count attack traffic ", err)
end
end
local today = get_today() .. '_'
local type_key = ATTACK_TYPE_PREFIX .. today .. rule_type
count, err = dict:incr(type_key, 1, 0, expire_time)
if not count and err == "not found" then
dict:set(type_key, 1, expire_time)
ngx.log(ngx.ERR, "failed to count attack traffic ", err)
end
end
local function count_not_found()
if ngx.status ~= 404 then
return
end
if config.is_global_state_on("notFoundCount") then
local ip = ngx.ctx.ip
local not_found_config = config.get_global_config("notFoundCount")
local key = ip
if config.is_redis_on() then
key = "cc_attack_count:" .. key
local count, _ = redis_util.incr(key, not_found_config.duration)
if not count then
redis_util.set(key, 1, not_found_config.duration)
elseif count >= not_found_config.threshold then
action.block_ip(ip, not_found_config)
return
end
else
key = ip .. "not_found"
local limit = ngx.shared.waf_limit
local count, _ = limit:incr(key, 1, 0, not_found_config.duration)
if not count then
limit:set(key, 1, not_found_config.duration)
elseif count >= not_found_config.threshold then
action.block_ip(ip, not_found_config)
return
end
end
end
end
if config.is_waf_on() then
count_not_found()
countRequestTraffic()
local isAttack = ngx.ctx.isAttack
if isAttack then
writeAttackLog()
countAttackRequestTraffic()
end
-- if ngx.ctx.ipBlocked then
-- writeIPBlockLog()
-- end
end