feat(waf): 优化规则 (#4166)

This commit is contained in:
zhengkunwang 2024-03-12 20:34:07 +08:00 committed by GitHub
parent 3b697c7520
commit 77f4f64f0d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
25 changed files with 813 additions and 10385 deletions

View file

@ -2225,6 +2225,20 @@ const message = {
ipEnd: 'End IP', ipEnd: 'End IP',
ipv4: 'IPV4', ipv4: 'IPV4',
ipv6: 'IPV6', ipv6: 'IPV6',
urlDefense: 'URL rules',
urlHelper: 'Forbidden URL',
dirFilter: 'Directory filter',
sqlInject: 'SQL injection',
xss: 'XSS',
phpExec: 'PHP script execution',
oneWordTrojan: 'One word Trojan',
appFilter: 'Apply dangerous directory filtering',
webshell: 'Webshell',
args: 'Malicious parameters',
protocolFilter: 'Protocol filter',
javaFileter: 'Java Dangerous File Filtering',
scannerFilter: 'Scanner filter',
escapeFilter: 'escape filter',
}, },
monitor: { monitor: {
name: 'Website Monitor', name: 'Website Monitor',
@ -2259,7 +2273,7 @@ const message = {
disableHelper: disableHelper:
'The anti-tampering function of website {0} is about to be disabled. Do you want to continue?', 'The anti-tampering function of website {0} is about to be disabled. Do you want to continue?',
}, },
setting: { setting: {
setting: 'Interface Settings', setting: 'Interface Settings',
title: 'Panel Description', title: 'Panel Description',
titleHelper: titleHelper:

View file

@ -2079,6 +2079,20 @@ const message = {
ipEnd: '結束 IP', ipEnd: '結束 IP',
ipv4: 'IPV4', ipv4: 'IPV4',
ipv6: 'IPV6', ipv6: 'IPV6',
urlDefense: 'URL 規則',
urlHelper: '禁止存取的 URL',
dirFilter: '目錄過濾',
sqlInject: 'SQL 注入',
xss: 'XSS',
phpExec: 'PHP 腳本執行',
oneWordTrojan: '一句話木馬',
appFilter: '套用危險目錄過濾',
webshell: 'Webshell',
args: '惡意參數',
protocolFilter: '協議過濾',
javaFileter: 'Java 危險檔案過濾',
scannerFilter: '掃描器過濾',
escapeFilter: '轉義過濾',
}, },
monitor: { monitor: {
name: '網站監控', name: '網站監控',

View file

@ -2056,13 +2056,13 @@ const message = {
sqliHelper: '识别请求中的 SQL 注入并拦截', sqliHelper: '识别请求中的 SQL 注入并拦截',
xssHelper: '识别请求中的 XSS 并拦截', xssHelper: '识别请求中的 XSS 并拦截',
xssDefense: 'XSS 防御', xssDefense: 'XSS 防御',
uaDefense: '恶意 User-Agent 规则', uaDefense: 'User-Agent 规则',
uaHelper: '包含常见的恶意爬虫规则', uaHelper: '包含常见的恶意爬虫规则',
argsDefense: '恶意参数规则', argsDefense: '参数规则',
argsHelper: '禁止请求中携带恶意参数', argsHelper: '禁止请求中携带恶意参数',
cookieDefense: '恶意 Cookie 规则', cookieDefense: 'Cookie 规则',
cookieHelper: '禁止请求中携带恶意 Cookie', cookieHelper: '禁止请求中携带恶意 Cookie',
headerDefense: '恶意 Header 规则', headerDefense: 'Header 规则',
headerHelper: '禁止请求中携带恶意 Header', headerHelper: '禁止请求中携带恶意 Header',
httpRule: 'HTTP 请求方法规则', httpRule: 'HTTP 请求方法规则',
httpHelper: '限制网站的请求方法类型', httpHelper: '限制网站的请求方法类型',
@ -2079,6 +2079,20 @@ const message = {
ipEnd: '结束 IP', ipEnd: '结束 IP',
ipv4: 'IPV4', ipv4: 'IPV4',
ipv6: 'IPV6', ipv6: 'IPV6',
urlDefense: 'URL 规则',
urlHelper: '禁止访问的 URL',
dirFilter: '目录过滤',
sqlInject: 'SQL 注入',
xss: 'XSS',
phpExec: 'PHP 脚本执行',
oneWordTrojan: '一句话木马',
appFilter: '应用危险目录过滤',
webshell: 'Webshell',
args: '恶意参数',
protocolFilter: '协议过滤',
javaFileter: 'Java 危险文件过滤',
scannerFilter: '扫描器过滤',
escapeFilter: '转义过滤',
}, },
monitor: { monitor: {
name: '网站监控', name: '网站监控',

View file

@ -39,7 +39,7 @@
"action": "deny" "action": "deny"
}, },
"notFoundCount": { "notFoundCount": {
"state": "on", "state": "off",
"type": "notFoundCount", "type": "notFoundCount",
"threshold": 10, "threshold": 10,
"duration": 60, "duration": 60,
@ -85,18 +85,18 @@
"action": "deny" "action": "deny"
}, },
"cc": { "cc": {
"state": "on", "state": "off",
"type": "cc", "type": "cc",
"rule": "cc", "rule": "cc",
"tokenTimeOut": 1800, "tokenTimeOut": 1800,
"threshold": 100, "threshold": 120,
"duration": 60, "duration": 60,
"action": "deny", "action": "deny",
"ipBlock": "on", "ipBlock": "on",
"ipBlockTime": 600 "ipBlockTime": 600
}, },
"ccurl": { "ccurl": {
"state": "on", "state": "off",
"type": "urlcc", "type": "urlcc",
"rule": "urlcc", "rule": "urlcc",
"action": "deny", "action": "deny",
@ -104,7 +104,7 @@
"ipBlockTime": 600 "ipBlockTime": 600
}, },
"attackCount": { "attackCount": {
"state": "on", "state": "off",
"type": "attackCount", "type": "attackCount",
"threshold": 20, "threshold": 20,
"duration": 60, "duration": 60,
@ -143,6 +143,12 @@
"code": 403, "code": 403,
"action": "deny" "action": "deny"
}, },
"defaultUrlBlack": {
"type": "defaultUrlBlack",
"state": "on",
"code": 403,
"action": "deny"
},
"args": { "args": {
"type": "args", "type": "args",
"state": "on", "state": "on",

View file

@ -83,6 +83,7 @@ local function init_global_config()
rules.args = read_rule(global_rule_dir, "args") rules.args = read_rule(global_rule_dir, "args")
rules.cookie = read_rule(global_rule_dir, "cookie") rules.cookie = read_rule(global_rule_dir, "cookie")
rules.defaultUaBlack = read_rule(global_rule_dir, "defaultUaBlack") rules.defaultUaBlack = read_rule(global_rule_dir, "defaultUaBlack")
rules.defaultUrlBlack = read_rule(global_rule_dir, "defaultUrlBlack")
rules.header = read_rule(global_rule_dir, "header") rules.header = read_rule(global_rule_dir, "header")
config.global_rules = rules config.global_rules = rules
@ -101,6 +102,7 @@ local function init_global_config()
_M.waf_dir = waf_dir _M.waf_dir = waf_dir
_M.waf_db_dir = waf_dir .. "db/" _M.waf_db_dir = waf_dir .. "db/"
_M.waf_db_path = _M.waf_db_dir .. "1pwaf.db" _M.waf_db_path = _M.waf_db_dir .. "1pwaf.db"
_M.waf_log_db_path = _M.waf_db_dir .. "req_log.db"
_M.config_dir = config_dir _M.config_dir = config_dir
end end

View file

@ -28,7 +28,7 @@ local function check_table(table_name,wafdb)
return rows > 0 return rows > 0
end end
function _M.init() local function init_db_config(db_path)
local ok, sqlite3 = pcall(function() local ok, sqlite3 = pcall(function()
return require "lsqlite3" return require "lsqlite3"
end) end)
@ -36,8 +36,7 @@ function _M.init()
return false return false
end end
local wafdb local wafdb
init_dir(config.waf_db_dir) wafdb = sqlite3.open(db_path)
wafdb = sqlite3.open(config.waf_db_path)
if wafdb == nil then if wafdb == nil then
return false return false
end end
@ -45,50 +44,17 @@ function _M.init()
wafdb:exec([[PRAGMA synchronous = 0]]) wafdb:exec([[PRAGMA synchronous = 0]])
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
end
function _M.init()
init_dir(config.waf_db_dir)
local wafdb = init_db_config(config.waf_db_path)
if not wafdb then
return false
end
local status = {} local status = {}
if not check_table("attack_log",wafdb) then
status = wafdb:exec([[
CREATE TABLE req_logs (
id TEXT PRIMARY KEY,
ip TEXT,
ip_iso TEXT,
ip_country_zh TEXT,
ip_country_en TEXT,
ip_province_zh TEXT,
ip_province_en TEXT,
ip_longitude TEXT,
ip_latitude TEXT,
time INTEGER,
localtime TEXT,
server_name TEXT,
website_key TEXT,
host TEXT,
method TEXT,
uri TEXT,
user_agent TEXT,
rule_type TEXT,
match_rule TEXT,
match_value TEXT,
nginx_log TEXT,
blocking_time INTEGER,
action TEXT,
is_block INTEGER,
is_attack INTEGER
)]])
end
if not check_table("block_ip",wafdb) then
status = wafdb:exec([[
CREATE TABLE block_ip (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ip TEXT,
is_block INTEGER,
attack_log_id INTEGER
)]])
ngx.log(ngx.ERR, "init block_ip status"..status)
end
if not check_table("waf_stat",wafdb) then if not check_table("waf_stat",wafdb) then
status = wafdb:exec([[ status = wafdb:exec([[
CREATE TABLE waf_stat ( CREATE TABLE waf_stat (
@ -102,6 +68,51 @@ function _M.init()
)]]) )]])
ngx.log(ngx.ERR, "init waf_stat status"..status) ngx.log(ngx.ERR, "init waf_stat status"..status)
end end
local logdb = init_db_config(config.waf_log_db_path)
if not check_table("req_logs",logdb) then
status = logdb:exec([[
CREATE TABLE req_logs (
id TEXT PRIMARY KEY,
ip TEXT,
ip_iso TEXT,
ip_country_zh TEXT,
ip_country_en TEXT,
ip_province_zh TEXT,
ip_province_en TEXT,
ip_longitude TEXT,
ip_latitude TEXT,
localtime DATETIME,
server_name TEXT,
website_key TEXT,
host TEXT,
method TEXT,
uri TEXT,
user_agent TEXT,
exec_rule TEXT,
rule_type TEXT,
match_rule TEXT,
match_value TEXT,
nginx_log TEXT,
blocking_time INTEGER,
action TEXT,
is_block INTEGER,
is_attack INTEGER
)]])
end
if not check_table("block_ips",logdb) then
status = logdb:exec([[
CREATE TABLE block_ips (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ip TEXT,
is_block INTEGER,
blocking_time INTEGER,
req_log_id TEXT,
create_date DATETIME
)]])
ngx.log(ngx.ERR, "init block_ip status"..status)
end
ngx.log(ngx.ERR, "init db success") ngx.log(ngx.ERR, "init db success")
end end

View file

@ -1,6 +1,5 @@
local db = require "db" local db = require "db"
local config = require "config" local config = require "config"
local geoip = require "geoip"
config.load_config_file() config.load_config_file()
db.init() db.init()

View file

@ -38,11 +38,10 @@ end
function _M.block_ip(ip, rule) function _M.block_ip(ip, rule)
local ok, err = nil, nil local ok, err = nil, nil
local msg = "拉黑IP : " .. ip .. "国家 " .. ngx.ctx.geoip.country["zh"] local msg = "拉黑IP : " .. ip .. "国家 " .. ngx.ctx.ip_location.country["zh"]
if rule then if rule then
msg = msg .. " 规则 " .. rule.type msg = msg .. " 规则 " .. rule.type
end end
ngx.log(ngx.ERR, msg) ngx.log(ngx.ERR, msg)
if config.redis_on then if config.redis_on then
@ -56,7 +55,7 @@ function _M.block_ip(ip, rule)
if exists == 0 then if exists == 0 then
ok, err = red:set(key, 1) ok, err = red:set(key, 1)
if ok then if ok then
ngx.ctx.ipBlocked = true ngx.ctx.ip_blocked = true
else else
ngx.log(ngx.ERR, "failed to set redis key " .. key, err) ngx.log(ngx.ERR, "failed to set redis key " .. key, err)
end end
@ -76,14 +75,14 @@ function _M.block_ip(ip, rule)
if not exists then if not exists then
ok, err = wafBlackIp:set(ip, 1, rule.ipBlockTime) ok, err = wafBlackIp:set(ip, 1, rule.ipBlockTime)
if ok then if ok then
ngx.ctx.ipBlocked = true ngx.ctx.ip_blocked = true
else else
ngx.log(ngx.ERR, "failed to set key " .. ip, err) ngx.log(ngx.ERR, "failed to set key " .. ip, err)
end end
elseif rule.ipBlockTime > 0 then elseif rule.ipBlockTime > 0 then
ok, err = wafBlackIp:expire(ip, rule.ipBlockTime) ok, err = wafBlackIp:expire(ip, rule.ipBlockTime)
if ok then if ok then
ngx.ctx.ipBlocked = true ngx.ctx.ip_blocked = true
else else
ngx.log(ngx.ERR, "failed to expire key " .. ip, err) ngx.log(ngx.ERR, "failed to expire key " .. ip, err)
end end
@ -128,15 +127,10 @@ end
function _M.exec_action(rule_config, match_rule, data) function _M.exec_action(rule_config, match_rule, data)
local action = rule_config.action local action = rule_config.action
if match_rule then if match_rule then
rule_config.rule = match_rule.rule rule_config.match_rule = match_rule
else
rule_config.rule = "默认"
end end
ngx.ctx.exec_rule = rule_config
ngx.ctx.rule_table = rule_config
ngx.ctx.action = action
ngx.ctx.hitData = data ngx.ctx.hitData = data
ngx.ctx.is_attack = true ngx.ctx.is_attack = true
@ -144,13 +138,12 @@ function _M.exec_action(rule_config, match_rule, data)
_M.block_ip(ngx.ctx.ip, rule_config) _M.block_ip(ngx.ctx.ip, rule_config)
end end
if rule_config.type == nil then
rule_config.type = "默认"
end
attack_count(rule_config.type) attack_count(rule_config.type)
local msg = "访问 IP " .. ngx.ctx.ip .. " 访问 URL" .. ngx.var.uri .. " 触发动作 " .. action .. " User-Agent " .. ngx.ctx.ua .. " 规则类型 " .. rule_config.type .. " 规则 " .. rule_config.rule local msg = "访问 IP " .. ngx.ctx.ip .. " 访问 URL" .. ngx.var.uri .. " 触发动作 " .. action .. " 规则类型 " .. rule_config.type
if match_rule then
msg = msg .. " 触发规则 " .. match_rule.type
end
ngx.log(ngx.ERR, msg) ngx.log(ngx.ERR, msg)
if action == "allow" then if action == "allow" then

View file

@ -6,7 +6,6 @@ local ck = require "resty.cookie"
local geo = require "geoip" local geo = require "geoip"
local libinjection = require "resty.libinjection" local libinjection = require "resty.libinjection"
local config = require "config" local config = require "config"
local cjson = require "cjson"
local utils = require "utils" local utils = require "utils"
local pairs = pairs local pairs = pairs
@ -14,12 +13,13 @@ local ipairs = ipairs
local tostring = tostring local tostring = tostring
local type = type local type = type
local next = next local next = next
local tonumber = tonumber
local concat_table = table.concat local concat_table = table.concat
local ngx_re_find = ngx.re.find local ngx_re_find = ngx.re.find
local decode = cjson.decode
local ngx_re_gmatch = ngx.re.gmatch local ngx_re_gmatch = ngx.re.gmatch
local ngx_re_match = ngx.re.match local ngx_re_match = ngx.re.match
local ipv4_to_int = utils.ipv4_to_int
local is_ip_in_array = utils.is_ip_in_array
local is_ipv6 = utils.is_ipv6
local exec_action = action.exec_action local exec_action = action.exec_action
@ -97,7 +97,7 @@ local function match_ip(ip_rule, ip, ipn)
return false return false
end end
local ip_rule_type = ip_rule.type local ip_rule_type = ip_rule.type
if utils.is_ipv6(ip) and ip_rule_type == "ipv6" then if is_ipv6(ip) and ip_rule_type == "ipv6" then
if ip == ip_rule.ipv6 then if ip == ip_rule.ipv6 then
return true return true
end end
@ -105,12 +105,13 @@ local function match_ip(ip_rule, ip, ipn)
end end
if ip_rule.type == "ipv4" then if ip_rule.type == "ipv4" then
if ipn == tonumber(ip_rule.ipv4) then if ipn == ipv4_to_int(ip_rule.ipv4) then
return true return true
end end
elseif ip_rule.type == "ipArr" then elseif ip_rule.type == "ipArr" then
local ipArr = ip_rule.ipArr local ip_start_n = ipv4_to_int(ip_rule.ipStart)
if utils.is_ip_in_array(ipn, ipArr.start, ipArr["end"]) then local ip_end_n = ipv4_to_int(ip_rule.ipEnd)
if is_ip_in_array(ipn, ip_start_n, ip_end_n) then
return true return true
end end
elseif ip_rule.type == "ipGroup" then elseif ip_rule.type == "ipGroup" then
@ -120,34 +121,50 @@ local function match_ip(ip_rule, ip, ipn)
return false return false
end end
local function xss_and_sql_check(body) local function get_boundary()
if body then local header = utils.get_headers()["content-type"]
if is_global_state_on("xss") or is_global_state_on("sql") then if not header then
for k, v in pairs(body) do return nil
if type(v) == 'string' then
if is_site_state_on("xss") then
local is_xss, fingerprint = libinjection.xss(tostring(v))
local xss_config = get_site_config("xss")
if is_xss then
exec_action(xss_config, { rule = tostring(k) .. '=' .. tostring(v) })
return
end
end
if is_site_state_on("sql") then
local is_sqli, fingerprint = libinjection.sqli(tostring(v))
local sql_config = get_site_config("sql")
if is_sqli then
exec_action(sql_config, { rule = tostring(k) .. '=' .. tostring(v) })
return
end
end
end
end
end
end end
if type(header) == "table" then
header = header[1]
end
local m = ngx_re_match(header, ";%s*boundary=\"([^\"]+)\"")
if m then
return m
end
return ngx_re_match(header, ";%s*boundary=([^\",;]+)")
end end
local function xss_and_sql_check(kv)
if type(kv) ~= 'string' then
return
end
if is_site_state_on("xss") then
local is_xss, fingerprint = libinjection.xss(tostring(kv))
local xss_config = get_site_config("xss")
if is_xss then
exec_action(xss_config, { rule = kv })
return
end
end
if is_site_state_on("sql") then
local is_sqli, fingerprint = libinjection.sqli(tostring(kv))
local sql_config = get_site_config("sql")
if is_sqli then
exec_action(sql_config, { rule = kv })
return
end
end
end
local function get_request_body() local function get_request_body()
ngx.req.read_body() ngx.req.read_body()
local body_data = ngx.req.get_body_data() local body_data = ngx.req.get_body_data()
@ -182,9 +199,9 @@ end
function _M.allow_location_check() function _M.allow_location_check()
if is_state_on("geoRestrict") then if is_state_on("geoRestrict") then
local geo_ip = ngx.ctx.geoip local ip_location = ngx.ctx.ip_location
if geo_ip and geo_ip.iso and geo_ip.iso ~= "" then if ip_location and ip_location.iso and ip_location.iso ~= "" then
local iso = geo_ip.iso local iso = ip_location.iso
local geo_config = get_site_config("geoRestrict") local geo_config = get_site_config("geoRestrict")
local exist = false local exist = false
for _, rule in ipairs(geo_config.rules) do for _, rule in ipairs(geo_config.rules) do
@ -233,7 +250,7 @@ function _M.black_ip()
if ip == "unknown" then if ip == "unknown" then
return false return false
end end
local exists = nil local exists = false
if config.is_redis_on() then if config.is_redis_on() then
exists = redis_util.get("black_ip:" .. ip) exists = redis_util.get("black_ip:" .. ip)
@ -241,14 +258,12 @@ function _M.black_ip()
exists = ngx.shared.waf_black_ip:get(ip) exists = ngx.shared.waf_black_ip:get(ip)
end end
if not exists then local ip_black_list = get_global_rules("ipBlack")
local ip_black_list = get_global_rules("ipBlack") local ipn = ipv4_to_int(ip)
local ipn = utils.ipv4_to_int(ip) for _, ip_rule in pairs(ip_black_list) do
for _, ip_rule in pairs(ip_black_list) do if match_ip(ip_rule, ip, ipn) then
if match_ip(ip_rule, ip, ipn) then exists = true
exists = true break
break
end
end end
end end
@ -424,6 +439,20 @@ function _M.black_url()
end end
end end
function _M.default_url_black()
if is_state_on("defaultUrlBlack") then
local url = ngx.var.uri
if url == nil or url == "" then
return false
end
local m, mr = match_rule(get_global_rules('defaultUrlBlack'), url)
if m then
exec_action(get_global_config('defaultUrlBlack'), mr)
return
end
end
end
function _M.args_check() function _M.args_check()
if is_state_on("args") then if is_state_on("args") then
local args = ngx.req.get_uri_args() local args = ngx.req.get_uri_args()
@ -436,13 +465,14 @@ 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
end end
xss_and_sql_check(val_arr)
end end
end end
xss_and_sql_check(args)
end end
end end
end end
@ -453,8 +483,7 @@ function _M.cookie_check()
local cookieList = get_site_rule('cookie') local cookieList = get_site_rule('cookie')
local m, mr = match_rule(cookieList, cookie) local m, mr = match_rule(cookieList, cookie)
if m then if m then
local rule_config = get_global_config('cookie') exec_action(get_global_config('cookie'), mr)
exec_action(rule_config, mr)
return true return true
end end
end end
@ -500,15 +529,10 @@ function _M.post_check()
return return
end end
if ngx_re_find(content_type, '^application/json', "ijo") then local boundary = get_boundary()
local data = get_request_body()
if data then
xss_and_sql_check(decode(data))
end
end
if is_site_state_on('fileExtCheck') and ngx_re_find(content_type, [[multipart]], 'ijo') then if boundary and is_site_state_on('fileExtCheck') then
if not ngx_re_match(content_type, '^multipart/form-data; boundary=') 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
local boundary_value = ngx_re_match(content_type, '^multipart/form-data; boundary=(.+)') local boundary_value = ngx_re_match(content_type, '^multipart/form-data; boundary=(.+)')
@ -541,6 +565,27 @@ function _M.post_check()
break break
end end
end end
else
ngx.req.read_body()
local body_obj = ngx.req.get_post_args()
if not body_obj then
return
end
for key, val in pairs(body_obj) do
if is_global_state_on("xss") or is_global_state_on("sql") then
xss_and_sql_check(key)
xss_and_sql_check(val)
end
if is_state_on("args") then
local post_rules = get_global_rules("args")
local m, mr = match_rule(post_rules, val)
if m then
exec_action(get_global_config("args"), mr)
return
end
end
end
end end
end end

View file

@ -7,6 +7,7 @@ local ipairs = ipairs
local type = type local type = type
local find_str = string.find local find_str = string.find
local gmatch_str = string.gmatch local gmatch_str = string.gmatch
local pcall = pcall
local cjson = require "cjson" local cjson = require "cjson"
local _M = {} local _M = {}
@ -116,15 +117,13 @@ function _M.get_real_ip()
return "unknown" return "unknown"
end end
function _M.get_geo_ip(ip) function _M.get_ip_location(ip)
if _M.is_intranet_address(ip) then if _M.is_intranet_address(ip) then
return { return {
country = { ["zh"] = "内网", ["en"] = "intranet" }, country = { ["zh"] = "内网", ["en"] = "Intranet" },
province = { ["zh"] = "内网", ["en"] = "intranet" },
city = { ["zh"] = "内网", ["en"] = "intranet" },
longitude = 0, longitude = 0,
latitude = 0, latitude = 0,
iso = "local" iso = "Local"
} }
else else
geoip.init() geoip.init()

View file

@ -7,103 +7,111 @@ local uuid = require"resty.uuid"
local upper_str = string.upper local upper_str = string.upper
local tonumber = tonumber local tonumber = tonumber
local pairs = pairs local pairs = pairs
local type = type
local concat_table = table.concat
local function write_req_log(wafdb,attack) local function write_req_log(attack)
local rule_table = nil local wafdb = utils.get_wafdb(config.waf_log_db_path)
local action = "" if not wafdb then
local rule = nil ngx.log(ngx.ERR, "get log db failed")
local rule_type = "" return
local is_attack = 0
local is_block = 0
local blocking_time = 0
if attack then
rule_table = ngx.ctx.rule_table
action = ngx.ctx.action
rule = rule_table.rule
rule_type = rule_table.type
is_attack = 1
if not rule_type then
rule_type = "default"
end
if ngx.ctx.ipBlocked then
is_block = 1
blocking_time = tonumber(rule_table.ipBlockTime)
end
end end
local real_ip = ngx.ctx.ip local real_ip = ngx.ctx.ip
local geoip = ngx.ctx.geoip local ip_location = ngx.ctx.ip_location
local country local country
local province local province
local longitude = 0.0 local longitude = 0.0
local latitude = 0.0 local latitude = 0.0
local iso = "CN" local iso = "CN"
if geoip then if ip_location then
country = geoip.country country = ip_location.country or {
province = geoip.province
longitude = geoip.longitude
latitude = geoip.latitude
iso = geoip.iso
else
ngx.log(ngx.ERR, real_ip .. " 无法获取地址")
end
if not country then
country = {
["zh"] = "unknown", ["zh"] = "unknown",
["en"] = "unknown" ["en"] = "unknown"
} }
end province = ip_location.province or {
if not province then ["zh"] = "",
province = { ["en"] = ""
["zh"] = "unknown",
["en"] = "unknown"
} }
longitude = ip_location.longitude
latitude = ip_location.latitude
iso = ip_location.iso
end end
local method = ngx.req.get_method() local exec_rule = {}
local uri = ngx.var.request_uri local rule_action = ""
local ua = ngx.ctx.ua local exec_rule_type = ""
local host = ngx.var.server_name local match_rule_detail = ""
local protocol = ngx.var.server_protocol local match_rule_type = ""
local website_key = ngx.ctx.website_key local is_attack = 0
local is_block = 0
local logs_str = method .. " " .. uri .. " "..protocol.."\n" local blocking_time = 0
local headers = ngx.req.get_headers(20000)
for k, v in pairs(headers) do local method = ""
local value = "" local uri = ""
if v then local ua = ""
if type(v) == "table" then local host = ""
value = table.concat(v, ",") local protocol = ""
else local website_key = ""
value = v local logs_str = ""
end
if attack then
exec_rule = ngx.ctx.exec_rule
rule_action = exec_rule.action
exec_rule_type = exec_rule.type
is_attack = 1
method = ngx.req.get_method()
uri = ngx.var.request_uri
ua = ngx.ctx.ua
host = ngx.var.server_name
protocol = ngx.var.server_protocol or ""
website_key = ngx.ctx.website_key
if exec_rule.match_rule then
match_rule_detail = exec_rule.match_rule.rule
match_rule_type = exec_rule.match_rule.type
end
if ngx.ctx.ip_blocked then
is_block = 1
blocking_time = tonumber(exec_rule.ipBlockTime)
end
logs_str = method .. " " .. uri .. " "..protocol.."\n"
local headers = ngx.req.get_headers(20000)
for k, v in pairs(headers) do
local value = ""
if v then
if type(v) == "table" then
value = concat_table(v, ",")
else
value = v
end
end
logs_str = logs_str .. upper_str(k) .. ": " .. value .. "\n"
end end
logs_str = logs_str .. upper_str(k) .. ": " .. value .. "\n"
end end
local log_id = uuid() local log_id = uuid()
local time = os.time()
local localtime = os.date("%Y-%m-%d %H:%M:%S", time)
local insertQuery = [[ local insertQuery = [[
INSERT INTO req_logs ( INSERT INTO req_logs (
id, ip, ip_iso, ip_country_zh, ip_country_en, id, ip, ip_iso, ip_country_zh, ip_country_en,
ip_province_zh, ip_province_en, ip_longitude, ip_latitude, ip_province_zh, ip_province_en, ip_longitude, ip_latitude,
time, localtime, server_name, website_key, host, method, localtime, server_name, website_key, host, method,
uri, user_agent, rule_type,match_rule, match_value, uri, user_agent, exec_rule, rule_type, match_rule, match_value,
nginx_log, blocking_time, action, is_block,is_attack nginx_log, blocking_time, action, is_block,is_attack
) VALUES ( ) VALUES (
:id, :real_ip, :iso, :country_zh, :country_en, :id, :real_ip, :iso, :country_zh, :country_en,
:province_zh, :province_en,:longitude, :latitude, :province_zh, :province_en,:longitude, :latitude,
:time, :localtime, :server_name,:host, :website_key, :method, DATETIME('now'), :server_name,:host, :website_key, :method,
:uri, :ua, :rule_type, :match_rule, :match_value, :uri, :ua, :exec_rule, :rule_type, :match_rule, :match_value,
:logs_str, :blocking_time, :action, :is_block, :is_attack :logs_str, :blocking_time, :action, :is_block, :is_attack
) )
]] ]]
wafdb:execute([[BEGIN TRANSACTION]])
local stmt = wafdb:prepare(insertQuery) local stmt = wafdb:prepare(insertQuery)
stmt:bind_names { stmt:bind_names {
id = log_id, id = log_id,
iso = iso, iso = iso,
@ -114,31 +122,48 @@ local function write_req_log(wafdb,attack)
province_en = province["en"], province_en = province["en"],
longitude = longitude, longitude = longitude,
latitude = latitude, latitude = latitude,
time = time,
localtime = localtime,
host = host, host = host,
server_name = host, server_name = host,
website_key = website_key, website_key = website_key,
method = method, method = method,
uri = uri, uri = uri,
ua = ua, ua = ua,
rule_type = rule_type, exec_rule = exec_rule_type,
match_rule = rule, rule_type = match_rule_type,
match_rule = match_rule_detail,
match_value = "", match_value = "",
logs_str = logs_str, logs_str = logs_str,
blocking_time = blocking_time or 0, blocking_time = blocking_time or 0,
action = action, action = rule_action,
is_block = is_block, is_block = is_block,
is_attack = is_attack is_attack = is_attack
} }
local code = stmt:step() local code = stmt:step()
stmt:finalize() stmt:finalize()
if code ~= 101 then local code2 = 101
local errorMsg = wafdb:errmsg() if ngx.ctx.ip_blocked then
if errorMsg then local insertBlockIp = [[
ngx.log(ngx.ERR, "insert attack_log error ", errorMsg .. " ") INSERT INTO block_ips (ip, is_block, blocking_time, req_log_id,create_date)
VALUES (:ip, :is_block, :blocking_time, :req_log_id, DATETIME('now'))
]]
stmt = wafdb:prepare(insertBlockIp)
stmt:bind_names {
ip=real_ip,
is_block = is_block,
blocking_time = blocking_time or 0,
req_log_id = log_id
}
code2 = stmt:step()
stmt:finalize()
end
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 end
end end
@ -176,7 +201,13 @@ local function count_not_found()
end end
end end
local function count_req_status(wafdb,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 today = ngx.today()
local status = ngx.status local status = ngx.status
@ -184,7 +215,8 @@ local function count_req_status(wafdb,is_attack)
stmt_exist:bind_values(today) stmt_exist:bind_values(today)
stmt_exist:step() stmt_exist:step()
local count = stmt_exist:get_uvalues() local count = stmt_exist:get_uvalues()
stmt_exist:finalize()
local req_count_update = 1 local req_count_update = 1
local count_4xx_update = (status >= 400 and status < 500) and 1 or 0 local count_4xx_update = (status >= 400 and status < 500) and 1 or 0
local count_5xx_update = (status >= 500) and 1 or 0 local count_5xx_update = (status >= 500) and 1 or 0
@ -204,9 +236,9 @@ local function count_req_status(wafdb,is_attack)
end end
if code ~= 101 then if code ~= 101 then
local errorMsg = wafdb:errmsg() local error_msg = wafdb:errmsg()
if errorMsg then if error_msg then
ngx.log(ngx.ERR, "update waf_stat error ", errorMsg .. " ") ngx.log(ngx.ERR, "update waf_stat error ", error_msg .. " ")
end end
end end
end end
@ -217,17 +249,13 @@ 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.geoip = utils.get_geo_ip(ngx.ctx.ip) ngx.ctx.ip_location = utils.get_ip_location(ngx.ctx.ip)
local ua = utils.get_header("user-agent") local ua = utils.get_header("user-agent")
if not ua then if not ua then
ua = "" ua = ""
end end
end end
count_req_status(is_attack)
local wafdb = utils.get_wafdb(config.waf_db_path) write_req_log(is_attack)
if wafdb ~= nil then
count_req_status(wafdb,is_attack)
write_req_log(wafdb,is_attack)
end
end end

View file

@ -2,87 +2,144 @@
"rules": [ "rules": [
{ {
"state": "on", "state": "on",
"rule": "select.+(from|limit)" "name": "sqlInject1",
"rule": "select.+(from|limit)",
"type": "sqlInject"
}, },
{ {
"state": "on", "state": "on",
"rule": "(?:(union(.*?)select))" "name": "sqlInject2",
"rule": "(?:(union(.*?)select))",
"type": "sqlInject"
}, },
{ {
"state": "on", "state": "on",
"rule": "having|rongjitest" "name": "sqlInject3",
"rule": "having|rongjitest",
"type": "sqlInject"
}, },
{ {
"state": "on", "state": "on",
"rule": "sleep\\((\\s*)(\\d*)(\\s*)\\)" "name": "sqlInject4",
"rule": "sleep\\((\\s*)(\\d*)(\\s*)\\)",
"type": "sqlInject"
}, },
{ {
"state": "on", "state": "on",
"rule": "benchmark\\((.*)\\,(.*)\\)" "name": "sqlInject5",
"rule": "benchmark\\((.*)\\,(.*)\\)",
"type": "sqlInject"
}, },
{ {
"state": "on", "state": "on",
"rule": "(?:from\\W+information_schema\\W)" "name": "sqlInject6",
"rule": "group\\s+by.+\\(",
"type": "sqlInject"
}, },
{ {
"state": "on", "state": "on",
"rule": "(?:(?:current_)user|database|schema|connection_id)\\s*\\(" "name": "sqlInject7",
"rule": "(?:from\\W+information_schema\\W)",
"type": "sqlInject"
}, },
{ {
"state": "on", "state": "on",
"rule": "(?:etc\\/\\W*passwd)" "name": "sqlInject8",
"rule": "(?:(?:current_)user|database|schema|connection_id)\\s*\\(",
"type": "sqlInject"
}, },
{ {
"state": "on", "state": "on",
"rule": "into(\\s+)+(?:dump|out)file\\s*" "name": "sqlInject9",
"rule": "into(\\s+)+(?:dump|out)file\\s*",
"type": "sqlInject"
}, },
{ {
"state": "on", "state": "on",
"rule": "group\\s+by.+\\(" "name": "sqlInject10",
"rule": "\\s+(or|xor|and)\\s+.*(=|<|>|'|\")",
"type": "sqlInject"
}, },
{ {
"state": "on", "state": "on",
"rule": "xwork.MethodAccessor" "name": "args1",
"rule": "xwork.MethodAccessor",
"type": "args",
"description": "Struts 恶意参数过滤"
}, },
{ {
"state": "on", "state": "on",
"rule": "(?:define|eval|file_get_contents|include|require|require_once|shell_exec|phpinfo|system|passthru|preg_\\w+|execute|echo|print|print_r|var_dump|(fp)open|alert|showmodaldialog)\\(" "name": "args2",
"rule": "xwork\\.MethodAccessor",
"type": "args",
"description": "Struts 恶意参数过滤"
}, },
{ {
"state": "on", "state": "on",
"rule": "xwork\\.MethodAccessor" "name": "oneWordTrojan1",
"rule": "(?:define|eval|file_get_contents|include|require|require_once|shell_exec|phpinfo|system|passthru|preg_\\w+|execute|echo|print|print_r|var_dump|(fp)open|alert|showmodaldialog)\\(",
"type": "oneWordTrojan"
}, },
{ {
"state": "on", "state": "on",
"rule": "(gopher|doc|php|glob|file|phar|zlib|ftp|ldap|dict|ogg|data)\\:\\/" "name": "oneWordTrojan2",
"rule": "\\$_(GET|post|cookie|files|session|env|phplib|GLOBALS|SERVER)\\[",
"type": "oneWordTrojan"
}, },
{ {
"state": "on", "state": "on",
"rule": "java\\.lang" "name": "protocolFilter1",
"rule": "(gopher|doc|php|glob|file|phar|zlib|ftp|ldap|dict|ogg|data)\\:\\/",
"type": "protocolFilter",
"description": "协议过滤"
}, },
{ {
"state": "on", "state": "on",
"rule": "\\$_(GET|post|cookie|files|session|env|phplib|GLOBALS|SERVER)\\[" "name": "dirFilter1",
"rule": "(?:etc\\/\\W*passwd)",
"type": "dirFilter"
}, },
{ {
"state": "on", "state": "on",
"rule": "\\<(iframe|script|body|img|layer|div|meta|style|base|object|input)" "name": "dirFilter2",
"rule": "java\\.lang",
"type": "dirFilter"
}, },
{ {
"state": "on", "state": "on",
"rule": "(onmouseover|onerror|onload)\\=" "name": "xss1",
"rule": "\\<(iframe|script|body|img|layer|div|meta|style|base|object|input)",
"type": "xss"
}, },
{ {
"state": "on", "state": "on",
"rule": "/shell?cd+/tmp;\\s*rm+-rf\\+\\*;\\s*wget" "name": "xss2",
"rule": "(onmouseover|onerror|onload)\\=",
"type": "xss"
}, },
{ {
"state": "on", "state": "on",
"rule": "/systembc/password.php" "name": "xss3",
"rule": "base64_decode\\(",
"type": "xss"
},
{
"state": "on",
"name": "webshell1",
"rule": "/shell?cd+/tmp;\\s*rm+-rf\\+\\*;\\s*wget",
"type": "webshell"
},
{
"state": "on",
"name": "phpExec1",
"rule": "/systembc/password.php",
"type": "phpExec"
}, },
{ {
"state":"on", "state":"on",
"rule":"(Acunetix-Aspect|Acunetix-Aspect-Password|Acunetix-Aspect-Queries|X-WIPP|X-RequestManager-Memo|X-Request-Memo|X-Scan-Memo)" "name": "scannerFilter1",
"rule":"(Acunetix-Aspect|Acunetix-Aspect-Password|Acunetix-Aspect-Queries|X-WIPP|X-RequestManager-Memo|X-Request-Memo|X-Scan-Memo)",
"type": "scannerFilter"
} }
] ]
} }

View file

@ -2,87 +2,137 @@
"rules": [ "rules": [
{ {
"state": "on", "state": "on",
"rule": "\\.\\./" "name": "dirFilter1",
"rule": "\\.\\./",
"type": "dirFilter"
}, },
{ {
"state": "on", "state": "on",
"rule": "\\:\\$" "name": "dirFilter2",
"rule": "\\:\\$",
"type": "dirFilter"
}, },
{ {
"state": "on", "state": "on",
"rule": "\\$\\{" "name": "dirFilter3",
"rule": "\\$\\{",
"type": "dirFilter"
}, },
{ {
"state": "on", "state": "on",
"rule": "select.+(from|limit)" "name": "dirFilter4",
"rule": "(?:etc\\/\\W*passwd)",
"type": "dirFilter"
}, },
{ {
"state": "on", "state": "on",
"rule": "(?:(union(.*?)select))" "name": "dirFilter5",
"rule": "java\\.lang",
"type": "dirFilter"
}, },
{ {
"state": "on", "state": "on",
"rule": "having|rongjitest" "name": "sqlInject1",
"rule": "select.+(from|limit)",
"type": "sqlInject"
}, },
{ {
"state": "on", "state": "on",
"rule": "sleep\\((\\s*)(\\d*)(\\s*)\\)" "name": "sqlInject2",
"rule": "(?:(union(.*?)select))",
"type": "sqlInject"
}, },
{ {
"state": "on", "state": "on",
"rule": "benchmark\\((.*)\\,(.*)\\)" "name": "sqlInject3",
"rule": "having|rongjitest",
"type": "sqlInject"
}, },
{ {
"state": "on", "state": "on",
"rule": "base64_decode\\(" "name": "sqlInject4",
"rule": "sleep\\((\\s*)(\\d*)(\\s*)\\)",
"type": "sqlInject"
}, },
{ {
"state": "on", "state": "on",
"rule": "(?:from\\W+information_schema\\W)" "name": "sqlInject5",
"rule": "benchmark\\((.*)\\,(.*)\\)",
"type": "sqlInject"
}, },
{ {
"state": "on", "state": "on",
"rule": "(?:(?:current_)user|database|schema|connection_id)\\s*\\(" "name": "sqlInject6",
"rule": "group\\s+by.+\\(",
"type": "sqlInject"
}, },
{ {
"state": "on", "state": "on",
"rule": "(?:etc\\/\\W*passwd)" "name": "sqlInject7",
"rule": "(?:from\\W+information_schema\\W)",
"type": "sqlInject"
}, },
{ {
"state": "on", "state": "on",
"rule": "into(\\s+)+(?:dump|out)file\\s*" "name": "sqlInject8",
"rule": "(?:(?:current_)user|database|schema|connection_id)\\s*\\(",
"type": "sqlInject"
}, },
{ {
"state": "on", "state": "on",
"rule": "group\\s+by.+\\(" "name": "sqlInject9",
"rule": "into(\\s+)+(?:dump|out)file\\s*",
"type": "sqlInject"
}, },
{ {
"state": "on", "state": "on",
"rule": "xwork.MethodAccessor" "name": "sqlInject10",
"rule": "\\s+(or|xor|and)\\s+.*(=|<|>|'|\")",
"type": "sqlInject"
}, },
{ {
"state": "on", "state": "on",
"rule": "(?:define|eval|file_get_contents|include|require|require_once|shell_exec|phpinfo|system|passthru|preg_\\w+|execute|echo|print|print_r|var_dump|(fp)open|alert|showmodaldialog)\\(" "name": "args1",
"rule": "xwork.MethodAccessor",
"type": "args",
"description": "Struts 恶意参数过滤"
}, },
{ {
"state": "on", "state": "on",
"rule": "xwork\\.MethodAccessor" "name": "args2",
"rule": "xwork\\.MethodAccessor",
"type": "args",
"description": "Struts 恶意参数过滤"
}, },
{ {
"state": "on", "state": "on",
"rule": "(gopher|doc|php|glob|file|phar|zlib|ftp|ldap|dict|ogg|data)\\:\\/" "name": "oneWordTrojan1",
"rule": "(?:define|eval|file_get_contents|include|require|require_once|shell_exec|phpinfo|system|passthru|preg_\\w+|execute|echo|print|print_r|var_dump|(fp)open|alert|showmodaldialog)\\(",
"type": "oneWordTrojan"
}, },
{ {
"state": "on", "state": "on",
"rule": "java\\.lang" "name": "oneWordTrojan2",
"rule": "\\$_(GET|post|cookie|files|session|env|phplib|GLOBALS|SERVER)\\[",
"type": "oneWordTrojan"
}, },
{ {
"state": "on", "state": "on",
"rule": "\\$_(GET|post|cookie|files|session|env|phplib|GLOBALS|SERVER)\\[" "name": "protocolFilter1",
"rule": "(gopher|doc|php|glob|file|phar|zlib|ftp|ldap|dict|ogg|data)\\:\\/",
"type": "protocolFilter"
}, },
{ {
"state":"on", "state":"on",
"rule":"(CustomCookie|acunetixCookie)" "name":"scannerFilter1",
"rule":"(CustomCookie|acunetixCookie)",
"type": "scannerFilter"
},
{
"state": "on",
"name": "xss1",
"rule": "base64_decode\\(",
"type": "xss"
} }
] ]
} }

View file

@ -1,16 +1,10 @@
{ {
"nextId": 3,
"rules": [ "rules": [
{ {
"id": 1,
"state": "on", "state": "on",
"type": "defaultUABlack", "name": "uaBlock1",
"action": "deny",
"rule": "HTTrack|Apache-HttpClient|harvest|audit|dirbuster|pangolin|nmap|sqln|hydra|Parser|libwww|BBBike|sqlmap|w3af|owasp|Nikto|fimap|havij|zmeu|BabyKrokodil|netsparker|httperf| SF/", "rule": "HTTrack|Apache-HttpClient|harvest|audit|dirbuster|pangolin|nmap|sqln|hydra|Parser|libwww|BBBike|sqlmap|w3af|owasp|Nikto|fimap|havij|zmeu|BabyKrokodil|netsparker|httperf| SF/",
"ipBlock": "on", "type": "scannerFilter"
"ipBlockTimeout": 600,
"code": 403,
"description": "一些不友好ua"
} }
] ]
} }

View file

@ -0,0 +1,82 @@
{
"rules": [
{
"state": "on",
"rule": "\\.(htaccess|mysql_history|bash_history|DS_Store|idea|user\\.ini)",
"name": "dirFilter1",
"type": "dirFilter"
},
{
"state": "on",
"rule": "\\.(bak|inc|old|mdb|sql|backup|java|class)$",
"name": "dirFilter2",
"type": "dirFilter"
},
{
"state": "on",
"rule": "^/(vhost|bbs|host|wwwroot|www|site|root|backup|data|ftp|db|admin|website|web).*\\.(rar|sql|zip|tar\\.gz|tar)$",
"name": "dirFilter3",
"type": "dirFilter"
},
{
"state": "on",
"rule": "java\\.lang",
"name": "dirFilter4",
"type": "dirFilter"
},
{
"state": "on",
"rule": "/(hack|shell|spy|phpspy)\\.php$",
"name": "phpExec1",
"type": "phpExec"
},
{
"state": "on",
"rule": "/(attachments|upimg|images|css|uploadfiles|html|uploads|templets|static|template|data|inc|forumdata|upload|includes|cache|avatar)/(\\\\w+).(php|jsp)",
"name": "phpExec2",
"type": "phpExec"
},
{
"state": "on",
"rule": "(?:phpMyAdmin2|phpMyAdmin|phpmyadmin|dbadmin|pma|myadmin|admin|mysql)/scripts/setup%.php",
"name": "phpExec3",
"type": "phpExec"
},
{
"state": "on",
"rule": "(?:define|eval|file_get_contents|include|require|require_once|shell_exec|phpinfo|system|passthru|preg_\\w+|execute|echo|print|print_r|var_dump|(fp)open|alert|showmodaldialog)\\(",
"name": "oneWordTrojan1",
"type": "oneWordTrojan"
},
{
"state": "on",
"rule": "(phpmyadmin|jmx-console|jmxinvokerservlet)",
"name": "appFilter1",
"type": "appFilter"
},
{
"state": "on",
"rule": "wp-includes/wlwmanifest.xml",
"name": "appFilter2",
"type": "appFilter"
},
{
"state": "on",
"rule": "<php>die(@md5(HelloThinkCMF))</php>",
"name": "appFilter3",
"type": "appFilter"
},
{
"state": "on",
"rule": "/boaform/admin/formLogin",
"name": "appFilter4",
"type": "appFilter"
},
{
"state": "on",
"rule": "(?:(union(.*?)select))",
"name": "sqlInject1",
"type": "sqlInject"
}
]
}

View file

@ -1,7 +1,22 @@
{ {
"rules":[ "rules": [
{"state":"on","rule":"/TomcatBypass/Command/Base64"}, {
{"state":"on","rule":"j\\S*ndi\\S*:\\S*(?:dap|dns)\\S+"}, "state": "on",
{"state":"on","rule":"(/acunetix-wvs-test-for-some-inexistent-file|netsparker|acunetix_wvs_security_test|AppScan|XSS@HERE)"} "name": "appFilter1",
"rule": "/TomcatBypass/Command/Base64",
"type": "appFilter"
},
{
"state": "on",
"name": "appFilter2",
"rule": "j\\S*ndi\\S*:\\S*(?:dap|dns)\\S+",
"type": "appFilter"
},
{
"state": "on",
"name": "scannerFilter1",
"rule": "(/acunetix-wvs-test-for-some-inexistent-file|netsparker|acunetix_wvs_security_test|AppScan|XSS@HERE)",
"type": "scannerFilter"
}
] ]
} }

View file

@ -4,7 +4,23 @@
"name": "拦截IP", "name": "拦截IP",
"state": "on", "state": "on",
"type": "ipv4", "type": "ipv4",
"ipv4": "123" "ipv4": "123",
"description": "拦截IP"
},
{
"name": "拦截IP",
"state": "on",
"type": "ipv6",
"ipv6": "kjdhsakjdhsakjdhakshd",
"description": "拦截IP"
},
{
"name": "拦截IP",
"state": "on",
"type": "ipArr",
"ipStart": "192.168.1.1",
"ipEnd": "192.168.1.10",
"description": "拦截IP"
} }
] ]
} }

File diff suppressed because it is too large Load diff

View file

@ -2,87 +2,129 @@
"rules": [ "rules": [
{ {
"state": "on", "state": "on",
"rule": "GET" "rule": "GET",
"name": "GET",
"type": "httpMethod"
}, },
{ {
"state": "on", "state": "on",
"rule": "POST" "rule": "POST",
"name": "POST",
"type": "httpMethod"
}, },
{ {
"state": "on", "state": "on",
"rule": "PUT" "rule": "PUT",
"name": "PUT",
"type": "httpMethod"
}, },
{ {
"state": "on", "state": "on",
"rule": "DELETE" "rule": "DELETE",
"name": "DELETE",
"type": "httpMethod"
}, },
{ {
"state": "on", "state": "on",
"rule": "PATCH" "rule": "PATCH",
"name": "PATCH",
"type": "httpMethod"
}, },
{ {
"state": "on", "state": "on",
"rule": "HEAD" "rule": "HEAD",
"name": "HEAD",
"type": "httpMethod"
}, },
{ {
"state": "on", "state": "on",
"rule": "OPTIONS" "rule": "OPTIONS",
"name": "OPTIONS",
"type": "httpMethod"
}, },
{ {
"state": "on", "state": "on",
"rule": "TRACE" "rule": "TRACE",
"name": "TRACE",
"type": "httpMethod"
}, },
{ {
"state": "on", "state": "on",
"rule": "CONNECT" "rule": "CONNECT",
"name": "CONNECT",
"type": "httpMethod"
}, },
{ {
"state": "on", "state": "on",
"rule": "PROPFIND" "rule": "PROPFIND",
"name": "PROPFIND",
"type": "httpMethod"
}, },
{ {
"state": "on", "state": "on",
"rule": "PROPPATCH" "rule": "PROPPATCH",
"name": "PROPPATCH",
"type": "httpMethod"
}, },
{ {
"state": "on", "state": "on",
"rule": "MKCOL" "rule": "MKCOL",
"name": "MKCOL",
"type": "httpMethod"
}, },
{ {
"state": "on", "state": "on",
"rule": "COPY" "rule": "COPY",
"name": "COPY",
"type": "httpMethod"
}, },
{ {
"state": "on", "state": "on",
"rule": "MOVE" "rule": "MOVE",
"name": "MOVE",
"type": "httpMethod"
}, },
{ {
"state": "on", "state": "on",
"rule": "LOCK" "rule": "LOCK",
"name": "LOCK",
"type": "httpMethod"
}, },
{ {
"state": "on", "state": "on",
"rule": "UNLOCK" "rule": "UNLOCK",
"name": "UNLOCK",
"type": "httpMethod"
}, },
{ {
"state": "on", "state": "on",
"rule": "LINK" "rule": "LINK",
"name": "LINK",
"type": "httpMethod"
}, },
{ {
"state": "on", "state": "on",
"rule": "UNLINK" "rule": "UNLINK",
"name": "UNLINK",
"type": "httpMethod"
}, },
{ {
"state": "on", "state": "on",
"rule": "WRAPPED" "rule": "WRAPPED",
"name": "WRAPPED",
"type": "httpMethod"
}, },
{ {
"state": "on", "state": "on",
"rule": "PROPFIND" "rule": "PROPFIND",
"name": "PROPFIND",
"type": "httpMethod"
}, },
{ {
"state": "on", "state": "on",
"rule": "SRARCH" "rule": "SRARCH",
"name": "SRARCH",
"type": "httpMethod"
} }
] ]
} }

View file

@ -1,23 +1,121 @@
{ {
"rules":[ "rules": [
{"state":"on","action":"deny","rule":"select.+(from|limit)"}, {
{"state":"on","action":"deny","rule":"(?:(union(.*?)select))"}, "state": "on",
{"state":"on","action":"deny","rule":"having|rongjitest"}, "name": "sqlInject1",
{"state":"on","action":"deny","rule":"sleep\\((\\s*)(\\d*)(\\s*)\\)"}, "rule": "select.+(from|limit)",
{"state":"on","action":"deny","rule":"benchmark\\((.*)\\,(.*)\\)"}, "type": "sqlInject"
{"state":"on","action":"deny","rule":"base64_decode\\("}, },
{"state":"on","action":"deny","rule":"(?:from\\W+information_schema\\W)"}, {
{"state":"on","action":"deny","rule":"(?:(?:current_)user|database|schema|connection_id)\\s*\\("}, "state": "on",
{"state":"on","action":"deny","rule":"(?:etc\\/\\W*passwd)"}, "name": "sqlInject2",
{"state":"on","action":"deny","rule":"into(\\s+)+(?:dump|out)file\\s*"}, "rule": "(?:(union(.*?)select))",
{"state":"on","action":"deny","rule":"group\\s+by.+\\("}, "type": "sqlInject"
{"state":"on","action":"deny","rule":"xwork.MethodAccessor"}, },
{"state":"on","action":"deny","rule":"(?:define|eval|file_get_contents|include|require|require_once|shell_exec|phpinfo|system|passthru|preg_\\w+|execute|echo|print|print_r|var_dump|(fp)open|alert|showmodaldialog)\\("}, {
{"state":"on","action":"deny","rule":"xwork\\.MethodAccessor"}, "state": "on",
{"state":"on","action":"deny","rule":"(gopher|doc|php|glob|file|phar|zlib|ftp|ldap|dict|ogg|data)\\:\\/"}, "name": "sqlInject3",
{"state":"on","action":"deny","rule":"java\\.lang"}, "rule": "having|rongjitest",
{"state":"on","action":"deny","rule":"\\$_(GET|post|cookie|files|session|env|phplib|GLOBALS|SERVER)\\["}, "type": "sqlInject"
{"state":"on","action":"deny","rule":"\\<(iframe|script|body|img|layer|div|meta|style|base|object|input)"}, },
{"state":"on","action":"deny","rule":"(onmouseover|onerror|onload)\\="} {
"state": "on",
"name": "sqlInject4",
"rule": "sleep\\((\\s*)(\\d*)(\\s*)\\)",
"type": "sqlInject"
},
{
"state": "on",
"name": "sqlInject5",
"rule": "benchmark\\((.*)\\,(.*)\\)",
"type": "sqlInject"
},
{
"state": "on",
"name": "sqlInject6",
"rule": "group\\s+by.+\\(",
"type": "sqlInject"
},
{
"state": "on",
"name": "sqlInject7",
"rule": "(?:from\\W+information_schema\\W)",
"type": "sqlInject"
},
{
"state": "on",
"name": "sqlInject8",
"rule": "(?:(?:current_)user|database|schema|connection_id)\\s*\\(",
"type": "sqlInject"
},
{
"state": "on",
"name": "sqlInject9",
"rule": "into(\\s+)+(?:dump|out)file\\s*",
"type": "sqlInject"
},
{
"state": "on",
"name": "args1",
"rule": "xwork.MethodAccessor",
"type": "args",
"description": "Struts 恶意参数过滤"
},
{
"state": "on",
"name": "args2",
"rule": "xwork\\.MethodAccessor",
"type": "args",
"description": "Struts 恶意参数过滤"
},
{
"state": "on",
"name": "oneWordTrojan1",
"rule": "(?:define|eval|file_get_contents|include|require|require_once|shell_exec|phpinfo|system|passthru|preg_\\w+|execute|echo|print|print_r|var_dump|(fp)open|alert|showmodaldialog)\\(",
"type": "oneWordTrojan"
},
{
"state": "on",
"name": "protocolFilter1",
"rule": "(gopher|doc|php|glob|file|phar|zlib|ftp|ldap|dict|ogg|data)\\:\\/",
"type": "protocolFilter",
"description": "协议过滤"
},
{
"state": "on",
"name": "oneWordTrojan2",
"rule": "\\$_(GET|post|cookie|files|session|env|phplib|GLOBALS|SERVER)\\[",
"type": "oneWordTrojan"
},
{
"state": "on",
"name": "xss1",
"rule": "\\<(iframe|script|body|img|layer|div|meta|style|base|object|input)",
"type": "xss"
},
{
"state": "on",
"name": "xss2",
"rule": "(onmouseover|onerror|onload)\\=",
"type": "xss"
},
{
"state": "on",
"name": "xss3",
"rule": "base64_decode\\(",
"type": "xss"
},
{
"state": "on",
"name": "dirFilter1",
"rule": "(?:etc\\/\\W*passwd)",
"type": "dirFilter"
},
{
"state": "on",
"name": "dirFilter2",
"rule": "java\\.lang",
"type": "dirFilter"
}
] ]
} }

View file

@ -1,5 +1,11 @@
{ {
"rules": [ "rules": [
{
"name": "UaBlack",
"state": "on",
"action": "deny",
"rule": "ua-blacklist",
"description": "测试"
}
] ]
} }

View file

@ -1,8 +1,3 @@
{ {
"rules": [ "rules": []
{
"state": "on",
"rule": "PostmanRuntime/7.36.1"
}
]
} }

View file

@ -1,44 +1,3 @@
{ {
"rules": [ "rules": []
{
"state": "on",
"rule": "\\.(svn|htaccess|bash_history)"
},
{
"state": "on",
"rule": "\\.(bak|inc|old|mdb|sql|backup|java|class)$"
},
{
"state": "on",
"rule": "(vhost|bbs|host|wwwroot|www|site|root|hytop|flashfxp).*\\.rar"
},
{
"state": "on",
"rule": "(phpmyadmin|jmx-console|jmxinvokerservlet)"
},
{
"state": "on",
"rule": "(?:phpMyAdmin2|phpMyAdmin|phpmyadmin|dbadmin|pma|myadmin|admin|mysql)/scripts/setup%.php"
},
{
"state": "on",
"rule": "java\\.lang"
},
{
"state": "on",
"rule": "/(attachments|upimg|images|css|uploadfiles|html|uploads|templets|static|template|data|inc|forumdata|upload|includes|cache|avatar)/(\\\\w+).(php|jsp)"
},
{
"state": "on",
"rule": "wp-includes/wlwmanifest.xml"
},
{
"state": "on",
"rule": "<php>die(@md5(HelloThinkCMF))</php>"
},
{
"state": "on",
"rule": "/boaform/admin/formLogin"
}
]
} }

View file

@ -1,14 +1,3 @@
{ {
"rules": [ "rules": []
{
"state": "on",
"action": "allow",
"rule": "/console/posts/editor"
},
{
"state": "on",
"action": "allow",
"rule": "/apis/api.console.halo.run/v1alpha1/posts"
}
]
} }

View file

@ -53,8 +53,7 @@ local function init()
end end
ngx.ctx.ua = ua ngx.ctx.ua = ua
ngx.ctx.geoip = utils.get_geo_ip(ip) ngx.ctx.ip_location = utils.get_ip_location(ip)
ngx.ctx.website_key = get_website_key() ngx.ctx.website_key = get_website_key()
ngx.ctx.method = ngx.req.get_method() ngx.ctx.method = ngx.req.get_method()
ngx.ctx.content_type = utils.get_header("content-type") ngx.ctx.content_type = utils.get_header("content-type")
@ -132,26 +131,27 @@ if config.is_waf_on() then
if lib.is_white_ip() then if lib.is_white_ip() then
return true return true
end end
lib.default_ip_black()
lib.black_ip() lib.black_ip()
lib.default_ip_black()
if lib.is_white_ua() then if lib.is_white_ua() then
return true return true
end end
lib.default_ua_black()
lib.black_ua() lib.black_ua()
lib.default_ua_black()
lib.cc_url() lib.cc_url()
if lib.is_white_url() then if lib.is_white_url() then
return true return true
end end
lib.black_url() lib.black_url()
lib.default_url_black()
lib.allow_location_check() lib.allow_location_check()
lib.acl()
lib.bot_check()
lib.method_check() lib.method_check()
lib.acl()
lib.cc() lib.cc()
lib.bot_check()
lib.args_check() lib.args_check()
lib.cookie_check() lib.cookie_check()
lib.post_check() lib.post_check()