1
0
mirror of https://github.com/1Panel-dev/1Panel.git synced 2025-01-31 22:18:07 +08:00

feat(waf): 优化请求次数记录方式 (#4210)

This commit is contained in:
zhengkunwang 2024-03-16 22:44:06 +08:00 committed by GitHub
parent 7784ee9575
commit cbfedb5d5e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 179 additions and 85 deletions

View File

@ -2167,7 +2167,7 @@ const message = {
count4xx: '4xx quantity', count4xx: '4xx quantity',
count5xx: '5xx quantity', count5xx: '5xx quantity',
todayStatus: 'Today Status', todayStatus: 'Today Status',
reqMap: 'Request map (30 days)', reqMap: 'Attack map (30 days)',
resource: 'source', resource: 'source',
count: 'Quantity', count: 'Quantity',
hight: 'high', hight: 'high',

View File

@ -2024,7 +2024,7 @@ const message = {
count4xx: '4xx 數量', count4xx: '4xx 數量',
count5xx: '5xx 數量', count5xx: '5xx 數量',
todayStatus: '今日狀態', todayStatus: '今日狀態',
reqMap: '請求地圖30', reqMap: '攔截地圖30',
resource: '來源', resource: '來源',
count: '數量', count: '數量',
hight: '高', hight: '高',

View File

@ -2025,7 +2025,7 @@ const message = {
count4xx: '4xx 数量', count4xx: '4xx 数量',
count5xx: '5xx 数量', count5xx: '5xx 数量',
todayStatus: '今日状态', todayStatus: '今日状态',
reqMap: '请求地图30', reqMap: '拦截地图30',
resource: '来源', resource: '来源',
count: '数量', count: '数量',
hight: '高', hight: '高',

View File

@ -1,7 +1,9 @@
{ {
"waf": "on", "waf": {
"state": "on",
"mode": "protection", "mode": "protection",
"secret": "qwer1234", "secret": "qwer1234"
},
"redis": { "redis": {
"state": "off", "state": "off",
"host": "127.0.0.1", "host": "127.0.0.1",
@ -11,7 +13,9 @@
"poolSize": 10 "poolSize": 10
}, },
"ipWhite": { "ipWhite": {
"state": "on" "state": "on",
"type": "ipWhite",
"action": "allow"
}, },
"ipBlack": { "ipBlack": {
"state": "on", "state": "on",
@ -21,7 +25,9 @@
"res": "ip" "res": "ip"
}, },
"urlWhite": { "urlWhite": {
"state": "on" "type": "urlWhite",
"state": "on",
"action": "allow"
}, },
"urlBlack": { "urlBlack": {
"type": "urlBlack", "type": "urlBlack",
@ -30,7 +36,9 @@
"action": "deny" "action": "deny"
}, },
"uaWhite": { "uaWhite": {
"state": "off" "type": "uaWhite",
"state": "off",
"action": "allow"
}, },
"uaBlack": { "uaBlack": {
"type": "uaBlack", "type": "uaBlack",
@ -64,7 +72,9 @@
"geoRestrict": { "geoRestrict": {
"state": "on", "state": "on",
"rules": [], "rules": [],
"action": "deny" "code": 444,
"action": "deny",
"type": "geoRestrict"
}, },
"defaultIpBlack": { "defaultIpBlack": {
"state": "on", "state": "on",
@ -87,7 +97,6 @@
"cc": { "cc": {
"state": "off", "state": "off",
"type": "cc", "type": "cc",
"rule": "cc",
"tokenTimeOut": 1800, "tokenTimeOut": 1800,
"threshold": 120, "threshold": 120,
"duration": 60, "duration": 60,
@ -98,7 +107,6 @@
"ccurl": { "ccurl": {
"state": "off", "state": "off",
"type": "urlcc", "type": "urlcc",
"rule": "urlcc",
"action": "deny", "action": "deny",
"ipBlock": "on", "ipBlock": "on",
"ipBlockTime": 600 "ipBlockTime": 600
@ -112,18 +120,11 @@
"ipBlock": "on", "ipBlock": "on",
"ipBlockTime": 600 "ipBlockTime": 600
}, },
"fileExtCheck": { "fileExt": {
"state": "on", "state": "on",
"action": "deny", "action": "deny",
"code": 403, "code": 403,
"type": "fileExtCheck", "type": "fileExtCheck"
"rules": [
"php",
"jsp",
"asp",
"exe",
"sh"
]
}, },
"cookie": { "cookie": {
"type": "cookie", "type": "cookie",

View File

@ -145,15 +145,15 @@ function _M.get_html_res(name)
end end
function _M.is_waf_on() function _M.is_waf_on()
return config.global_config["waf"] == "on" and true or false return _M.is_global_state_on("waf")
end end
function _M.is_redis_on() function _M.is_redis_on()
return config.global_config["redis"] == "on" and true or false return _M.is_global_state_on("redis")
end end
function _M.get_secret() function _M.get_secret()
return config.global_config["secret"] return config.global_config["waf"]["secret"]
end end
return _M return _M

View File

@ -35,13 +35,12 @@ local function init_db_config(db_path)
if not ok then if not ok then
return false return false
end end
local wafdb local wafdb = sqlite3.open(db_path)
wafdb = sqlite3.open(db_path)
if wafdb == nil then if wafdb == nil then
return false return false
end end
wafdb:exec([[PRAGMA journal_mode = wal]]) wafdb:exec([[PRAGMA journal_mode = wal]])
wafdb:exec([[PRAGMA synchronous = 0]]) wafdb:exec([[PRAGMA synchronous = OFF]])
wafdb:exec([[PRAGMA page_size = 8192]]) wafdb:exec([[PRAGMA page_size = 8192]])
wafdb:exec([[PRAGMA journal_size_limit = 2147483648]]) wafdb:exec([[PRAGMA journal_size_limit = 2147483648]])
return wafdb return wafdb

View File

@ -142,7 +142,11 @@ function _M.exec_action(rule_config, match_rule, data)
local msg = "访问 IP " .. ngx.ctx.ip .. " 访问 URL" .. ngx.var.uri .. " 触发动作 " .. action .. " 规则类型 " .. rule_config.type local msg = "访问 IP " .. ngx.ctx.ip .. " 访问 URL" .. ngx.var.uri .. " 触发动作 " .. action .. " 规则类型 " .. rule_config.type
if match_rule then if match_rule then
msg = msg .. " 触发规则 " .. match_rule.type if match_rule.type then
msg = msg .. " 触发规则类型 " .. match_rule.type
else
msg = msg .. " 触发规则 " .. match_rule.rule
end
end end
ngx.log(ngx.ERR, msg) ngx.log(ngx.ERR, msg)

View File

@ -465,7 +465,6 @@ function _M.args_check()
end end
if val_arr and type(val_arr) ~= "boolean" and val_arr ~= "" then if val_arr and type(val_arr) ~= "boolean" and val_arr ~= "" then
local m, mr = match_rule(args_list, utils.unescape_uri(val_arr)) local m, mr = match_rule(args_list, utils.unescape_uri(val_arr))
ngx.log(ngx.ERR, "args_check: ", m, " ", mr.rule, " ", val_arr)
if m then if m then
exec_action(get_global_config("args"), mr) exec_action(get_global_config("args"), mr)
return return
@ -531,7 +530,7 @@ function _M.post_check()
local boundary = get_boundary() local boundary = get_boundary()
if boundary and is_site_state_on('fileExtCheck') then if boundary and is_state_on('fileExt') then
if not ngx_re_match(content_type, '^multipart/form-data; boundary=') or not ngx_re_find(content_type, [[multipart]], 'ijo')then if not ngx_re_match(content_type, '^multipart/form-data; boundary=') or not ngx_re_find(content_type, [[multipart]], 'ijo')then
return return
end end
@ -548,7 +547,7 @@ function _M.post_check()
return return
end end
local rule = get_site_config("fileExtCheck") local rule = get_site_rule("fileExt")
while true do while true do
local m = iterator() local m = iterator()
if m then if m then

View File

@ -138,7 +138,7 @@ local function write_req_log(attack)
is_block = is_block, is_block = is_block,
is_attack = is_attack is_attack = is_attack
} }
local code = stmt:step() stmt:step()
stmt:finalize() stmt:finalize()
local code2 = 101 local code2 = 101
@ -160,12 +160,10 @@ local function write_req_log(attack)
wafdb:execute([[COMMIT]]) wafdb:execute([[COMMIT]])
if code ~= 101 or code2 ~= 101 then
local error_msg = wafdb:errmsg() local error_msg = wafdb:errmsg()
if error_msg then if error_msg then
ngx.log(ngx.ERR, "insert attack_log error ", error_msg .. " ") ngx.log(ngx.ERR, "insert attack_log error ", error_msg .. " ")
end end
end
end end
@ -201,45 +199,25 @@ local function count_not_found()
end end
end end
local add_count = function(shared_dict,key)
local count, _ = shared_dict:incr(key, 1)
if not count then
shared_dict:set(key, 1)
end
end
local function count_req_status(is_attack) local function count_req_status(is_attack)
local wafdb = utils.get_wafdb(config.waf_db_path)
if not wafdb then
ngx.log(ngx.ERR, "get log db failed")
return
end
local today = ngx.today()
local status = ngx.status local status = ngx.status
local req_count = ngx.shared.dict_req_count
local stmt_exist = wafdb:prepare("SELECT COUNT(*) FROM waf_stat WHERE day = ?") add_count(req_count, "req_count")
stmt_exist:bind_values(today) if (status >= 400 and status < 500) then
stmt_exist:step() add_count(req_count, "count_4xx")
local count = stmt_exist:get_uvalues()
stmt_exist:finalize()
local req_count_update = 1
local count_4xx_update = (status >= 400 and status < 500) and 1 or 0
local count_5xx_update = (status >= 500) and 1 or 0
local attack_count_update = is_attack and 1 or 0
local code = 0
if count > 0 then
local stmt = wafdb:prepare("UPDATE waf_stat SET req_count = req_count + ?, count4xx = count4xx + ?, count5xx = count5xx + ?, attack_count = attack_count + ? WHERE day = ?")
stmt:bind_values(req_count_update, count_4xx_update, count_5xx_update, attack_count_update, today)
code = stmt:step()
stmt:finalize()
else
local stmt = wafdb:prepare("INSERT INTO waf_stat (day, req_count, count4xx, count5xx, attack_count,create_date) VALUES (?, ?, ?, ?, ?,DATETIME('now'))")
stmt:bind_values(today, req_count_update, count_4xx_update, count_5xx_update, attack_count_update)
code = stmt:step()
stmt:finalize()
end end
if (status >= 500) then
if code ~= 101 then add_count(req_count, "count_5xx")
local error_msg = wafdb:errmsg()
if error_msg then
ngx.log(ngx.ERR, "update waf_stat error ", error_msg .. " ")
end end
if is_attack then
add_count(req_count, "attack_count")
end end
end end
@ -250,12 +228,10 @@ if config.is_waf_on() then
if not ngx.ctx.ip then if not ngx.ctx.ip then
ngx.ctx.ip = utils.get_real_ip() ngx.ctx.ip = utils.get_real_ip()
ngx.ctx.ip_location = utils.get_ip_location(ngx.ctx.ip) ngx.ctx.ip_location = utils.get_ip_location(ngx.ctx.ip)
local ua = utils.get_header("user-agent")
if not ua then
ua = ""
end
end end
count_req_status(is_attack) count_req_status(is_attack)
if is_attack then
write_req_log(is_attack) write_req_log(is_attack)
end
end end

View File

@ -2,21 +2,23 @@
"rules": [ "rules": [
{ {
"state": "on", "state": "on",
"rule": "no Cookie", "name": "no cookie",
"name": "拦截不带Cookie的请求",
"conditions": [ "conditions": [
{ {
"field": "URL", "field": "URL",
"pattern": "/test/\\d+\\.html" "pattern": "eq",
"rule": "/test/\\d+\\.html"
}, },
{ {
"field": "Cookie", "field": "Cookie",
"pattern": "" "pattern": "eq",
"rule": ""
} }
], ],
"action": "deny", "action": "deny",
"autoIpBlock": "off", "res": "",
"ipBlockTimeout": 60, "ipBlock": "off",
"ipBlockTime": 60,
"description": "拦截不带Cookie的请求" "description": "拦截不带Cookie的请求"
} }
] ]

View File

@ -0,0 +1,34 @@
{
"rules": [
{
"state": "on",
"rule": "php",
"name": "php",
"type": "fileExt"
},
{
"state": "on",
"rule": "jsp",
"name": "jsp",
"type": "fileExt"
},
{
"state": "on",
"rule": "asp",
"name": "asp",
"type": "fileExt"
},
{
"state": "on",
"rule": "exe",
"name": "exe",
"type": "fileExt"
},
{
"state": "on",
"rule": "sh",
"name": "sh",
"type": "fileExt"
}
]
}

View File

@ -0,0 +1,16 @@
{
"rules": [
{
"state": "on",
"name": "appFilter1",
"rule": "/TomcatBypass/Command/Base64",
"type": "appFilter"
},
{
"state": "on",
"name": "appFilter2",
"rule": "j\\S*ndi\\S*:\\S*(?:dap|dns)\\S+",
"type": "appFilter"
},
]
}

View File

@ -156,4 +156,5 @@ if config.is_waf_on() then
lib.cookie_check() lib.cookie_check()
lib.post_check() lib.post_check()
lib.header_check() lib.header_check()
end end

View File

@ -1,2 +1,64 @@
local uuid = require 'resty.uuid' local uuid = require 'resty.uuid'
local utils = require "utils"
local config = require "config"
uuid.seed() uuid.seed()
local update_req_count = function()
local req_count = ngx.shared.dict_req_count
local req_count_update = req_count:get("req_count") or 0
req_count:set("req_count", 0)
local count_4xx_update = req_count:get("count_4xx") or 0
req_count:set("count_4xx", 0)
local count_5xx_update = req_count:get("count_5xx") or 0
req_count:set("count_5xx", 0)
local attack_count_update = req_count:get("attack_count") or 0
req_count:set("attack_count", 0)
if req_count_update == 0 and count_4xx_update == 0 and count_5xx_update == 0 and attack_count_update == 0 then
return
end
local today = ngx.today()
local wafdb = utils.get_wafdb(config.waf_db_path)
if not wafdb then
ngx.log(ngx.ERR, "get log db failed")
return
end
wafdb:execute([[BEGIN TRANSACTION]])
local stmt_exist = wafdb:prepare("SELECT COUNT(*) FROM waf_stat WHERE day = ?")
stmt_exist:bind_values(today)
stmt_exist:step()
local count = stmt_exist:get_uvalues()
stmt_exist:finalize()
local code = 0
if count > 0 then
local stmt = wafdb:prepare("UPDATE waf_stat SET req_count = req_count + ?, count4xx = count4xx + ?, count5xx = count5xx + ?, attack_count = attack_count + ? WHERE day = ?")
stmt:bind_values(req_count_update, count_4xx_update, count_5xx_update, attack_count_update, today)
code = stmt:step()
stmt:finalize()
else
local stmt = wafdb:prepare("INSERT INTO waf_stat (day, req_count, count4xx, count5xx, attack_count,create_date) VALUES (?, ?, ?, ?, ?,DATETIME('now'))")
stmt:bind_values(today, req_count_update, count_4xx_update, count_5xx_update, attack_count_update)
code = stmt:step()
stmt:finalize()
end
wafdb:execute([[COMMIT]])
--local error_msg = wafdb:errmsg()
--if error_msg then
-- ngx.log(ngx.ERR, "update waf_stat error ", error_msg .. " ")
--end
end
if 0 == ngx.worker.id() then
local ok, err = ngx.timer.every(2, update_req_count)
if not ok then
ngx.log(ngx.ERR, "failed to create the timer: ", err)
return
end
end