diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index a6f99533e..b7256ed14 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -2167,7 +2167,7 @@ const message = { count4xx: '4xx quantity', count5xx: '5xx quantity', todayStatus: 'Today Status', - reqMap: 'Request map (30 days)', + reqMap: 'Attack map (30 days)', resource: 'source', count: 'Quantity', hight: 'high', diff --git a/frontend/src/lang/modules/tw.ts b/frontend/src/lang/modules/tw.ts index 9a2a6ffc1..67dc4b718 100644 --- a/frontend/src/lang/modules/tw.ts +++ b/frontend/src/lang/modules/tw.ts @@ -2024,7 +2024,7 @@ const message = { count4xx: '4xx 數量', count5xx: '5xx 數量', todayStatus: '今日狀態', - reqMap: '請求地圖(30日)', + reqMap: '攔截地圖(30日)', resource: '來源', count: '數量', hight: '高', diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index 7514a590b..a2b73c287 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -2025,7 +2025,7 @@ const message = { count4xx: '4xx 数量', count5xx: '5xx 数量', todayStatus: '今日状态', - reqMap: '请求地图(30日)', + reqMap: '拦截地图(30日)', resource: '来源', count: '数量', hight: '高', diff --git a/plugins/openresty/waf/conf/global.json b/plugins/openresty/waf/conf/global.json index c770b4aa8..d189f525a 100644 --- a/plugins/openresty/waf/conf/global.json +++ b/plugins/openresty/waf/conf/global.json @@ -1,7 +1,9 @@ { - "waf": "on", - "mode": "protection", - "secret": "qwer1234", + "waf": { + "state": "on", + "mode": "protection", + "secret": "qwer1234" + }, "redis": { "state": "off", "host": "127.0.0.1", @@ -11,7 +13,9 @@ "poolSize": 10 }, "ipWhite": { - "state": "on" + "state": "on", + "type": "ipWhite", + "action": "allow" }, "ipBlack": { "state": "on", @@ -21,7 +25,9 @@ "res": "ip" }, "urlWhite": { - "state": "on" + "type": "urlWhite", + "state": "on", + "action": "allow" }, "urlBlack": { "type": "urlBlack", @@ -30,7 +36,9 @@ "action": "deny" }, "uaWhite": { - "state": "off" + "type": "uaWhite", + "state": "off", + "action": "allow" }, "uaBlack": { "type": "uaBlack", @@ -64,7 +72,9 @@ "geoRestrict": { "state": "on", "rules": [], - "action": "deny" + "code": 444, + "action": "deny", + "type": "geoRestrict" }, "defaultIpBlack": { "state": "on", @@ -87,7 +97,6 @@ "cc": { "state": "off", "type": "cc", - "rule": "cc", "tokenTimeOut": 1800, "threshold": 120, "duration": 60, @@ -98,7 +107,6 @@ "ccurl": { "state": "off", "type": "urlcc", - "rule": "urlcc", "action": "deny", "ipBlock": "on", "ipBlockTime": 600 @@ -112,18 +120,11 @@ "ipBlock": "on", "ipBlockTime": 600 }, - "fileExtCheck": { + "fileExt": { "state": "on", "action": "deny", "code": 403, - "type": "fileExtCheck", - "rules": [ - "php", - "jsp", - "asp", - "exe", - "sh" - ] + "type": "fileExtCheck" }, "cookie": { "type": "cookie", diff --git a/plugins/openresty/waf/config.lua b/plugins/openresty/waf/config.lua index 0095e36c8..9d839393f 100644 --- a/plugins/openresty/waf/config.lua +++ b/plugins/openresty/waf/config.lua @@ -145,15 +145,15 @@ function _M.get_html_res(name) end function _M.is_waf_on() - return config.global_config["waf"] == "on" and true or false + return _M.is_global_state_on("waf") end function _M.is_redis_on() - return config.global_config["redis"] == "on" and true or false + return _M.is_global_state_on("redis") end function _M.get_secret() - return config.global_config["secret"] + return config.global_config["waf"]["secret"] end return _M \ No newline at end of file diff --git a/plugins/openresty/waf/db.lua b/plugins/openresty/waf/db.lua index f77a5f31e..792030adb 100644 --- a/plugins/openresty/waf/db.lua +++ b/plugins/openresty/waf/db.lua @@ -35,13 +35,12 @@ local function init_db_config(db_path) if not ok then return false end - local wafdb - wafdb = sqlite3.open(db_path) + local wafdb = sqlite3.open(db_path) if wafdb == nil then return false end 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 journal_size_limit = 2147483648]]) return wafdb diff --git a/plugins/openresty/waf/lib/action.lua b/plugins/openresty/waf/lib/action.lua index f346bd635..85eefef7d 100644 --- a/plugins/openresty/waf/lib/action.lua +++ b/plugins/openresty/waf/lib/action.lua @@ -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 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 ngx.log(ngx.ERR, msg) diff --git a/plugins/openresty/waf/lib/lib.lua b/plugins/openresty/waf/lib/lib.lua index 353f9bcfb..96497b3a0 100644 --- a/plugins/openresty/waf/lib/lib.lua +++ b/plugins/openresty/waf/lib/lib.lua @@ -465,7 +465,6 @@ function _M.args_check() end if val_arr and type(val_arr) ~= "boolean" and val_arr ~= "" then 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 exec_action(get_global_config("args"), mr) return @@ -531,7 +530,7 @@ function _M.post_check() 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 return end @@ -548,7 +547,7 @@ function _M.post_check() return end - local rule = get_site_config("fileExtCheck") + local rule = get_site_rule("fileExt") while true do local m = iterator() if m then diff --git a/plugins/openresty/waf/log_and_traffic.lua b/plugins/openresty/waf/log_and_traffic.lua index 955b17a5f..be81d416f 100644 --- a/plugins/openresty/waf/log_and_traffic.lua +++ b/plugins/openresty/waf/log_and_traffic.lua @@ -138,7 +138,7 @@ local function write_req_log(attack) is_block = is_block, is_attack = is_attack } - local code = stmt:step() + stmt:step() stmt:finalize() local code2 = 101 @@ -160,11 +160,9 @@ local function write_req_log(attack) wafdb:execute([[COMMIT]]) - if code ~= 101 or code2 ~= 101 then - local error_msg = wafdb:errmsg() - if error_msg then - ngx.log(ngx.ERR, "insert attack_log error ", error_msg .. " ") - end + local error_msg = wafdb:errmsg() + if error_msg then + ngx.log(ngx.ERR, "insert attack_log error ", error_msg .. " ") end end @@ -201,45 +199,25 @@ local function count_not_found() 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 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 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 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() + local req_count = ngx.shared.dict_req_count + add_count(req_count, "req_count") + if (status >= 400 and status < 500) then + add_count(req_count, "count_4xx") end - - if code ~= 101 then - local error_msg = wafdb:errmsg() - if error_msg then - ngx.log(ngx.ERR, "update waf_stat error ", error_msg .. " ") - end + if (status >= 500) then + add_count(req_count, "count_5xx") + end + if is_attack then + add_count(req_count, "attack_count") end end @@ -250,12 +228,10 @@ if config.is_waf_on() then if not ngx.ctx.ip then ngx.ctx.ip = utils.get_real_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 count_req_status(is_attack) - write_req_log(is_attack) + if is_attack then + write_req_log(is_attack) + end end diff --git a/plugins/openresty/waf/rules/acl.json b/plugins/openresty/waf/rules/acl.json index 93a40514b..6f86e8b3b 100644 --- a/plugins/openresty/waf/rules/acl.json +++ b/plugins/openresty/waf/rules/acl.json @@ -2,21 +2,23 @@ "rules": [ { "state": "on", - "rule": "no Cookie", - "name": "拦截不带Cookie的请求", + "name": "no cookie", "conditions": [ { "field": "URL", - "pattern": "/test/\\d+\\.html" + "pattern": "eq", + "rule": "/test/\\d+\\.html" }, { "field": "Cookie", - "pattern": "" + "pattern": "eq", + "rule": "" } ], "action": "deny", - "autoIpBlock": "off", - "ipBlockTimeout": 60, + "res": "", + "ipBlock": "off", + "ipBlockTime": 60, "description": "拦截不带Cookie的请求" } ] diff --git a/plugins/openresty/waf/rules/fileExt.json b/plugins/openresty/waf/rules/fileExt.json new file mode 100644 index 000000000..c0cc78781 --- /dev/null +++ b/plugins/openresty/waf/rules/fileExt.json @@ -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" + } + ] +} diff --git a/plugins/openresty/waf/rules/geoRestrict.json b/plugins/openresty/waf/rules/geoRestrict.json new file mode 100644 index 000000000..7769a81db --- /dev/null +++ b/plugins/openresty/waf/rules/geoRestrict.json @@ -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" + }, + ] +} \ No newline at end of file diff --git a/plugins/openresty/waf/waf.lua b/plugins/openresty/waf/waf.lua index 8c81d8236..396d18c2e 100644 --- a/plugins/openresty/waf/waf.lua +++ b/plugins/openresty/waf/waf.lua @@ -156,4 +156,5 @@ if config.is_waf_on() then lib.cookie_check() lib.post_check() lib.header_check() + end \ No newline at end of file diff --git a/plugins/openresty/waf/worker.lua b/plugins/openresty/waf/worker.lua index 50a484851..41564d1ea 100644 --- a/plugins/openresty/waf/worker.lua +++ b/plugins/openresty/waf/worker.lua @@ -1,2 +1,64 @@ local uuid = require 'resty.uuid' -uuid.seed() \ No newline at end of file +local utils = require "utils" +local config = require "config" + +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 \ No newline at end of file