mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-03-14 01:34:47 +08:00
feat(waf): 修改攻击日志格式 (#4024)
This commit is contained in:
parent
24f573f9fd
commit
94702a79a4
224
frontend/src/assets/json/name.json
Normal file
224
frontend/src/assets/json/name.json
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
{
|
||||||
|
"Afghanistan": "阿富汗",
|
||||||
|
"Singapore": "新加坡",
|
||||||
|
"Angola": "安哥拉",
|
||||||
|
"Albania": "阿尔巴尼亚",
|
||||||
|
"United Arab Emirates": "阿联酋",
|
||||||
|
"Argentina": "阿根廷",
|
||||||
|
"Armenia": "亚美尼亚",
|
||||||
|
"French Southern and Antarctic Lands": "法属南半球和南极领地",
|
||||||
|
"Australia": "澳大利亚",
|
||||||
|
"Austria": "奥地利",
|
||||||
|
"Azerbaijan": "阿塞拜疆",
|
||||||
|
"Burundi": "布隆迪",
|
||||||
|
"Belgium": "比利时",
|
||||||
|
"Benin": "贝宁",
|
||||||
|
"Burkina Faso": "布基纳法索",
|
||||||
|
"Bangladesh": "孟加拉国",
|
||||||
|
"Bulgaria": "保加利亚",
|
||||||
|
"The Bahamas": "巴哈马",
|
||||||
|
"Bosnia and Herzegovina": "波斯尼亚和黑塞哥维那",
|
||||||
|
"Belarus": "白俄罗斯",
|
||||||
|
"Belize": "伯利兹",
|
||||||
|
"Bermuda": "百慕大",
|
||||||
|
"Bolivia": "玻利维亚",
|
||||||
|
"Brazil": "巴西",
|
||||||
|
"Brunei": "文莱",
|
||||||
|
"Bhutan": "不丹",
|
||||||
|
"Botswana": "博茨瓦纳",
|
||||||
|
"Central African Republic": "中非共和国",
|
||||||
|
"Canada": "加拿大",
|
||||||
|
"Switzerland": "瑞士",
|
||||||
|
"Chile": "智利",
|
||||||
|
"China": "中国",
|
||||||
|
"Ivory Coast": "象牙海岸",
|
||||||
|
"Cameroon": "喀麦隆",
|
||||||
|
"Democratic Republic of the Congo": "刚果民主共和国",
|
||||||
|
"Republic of the Congo": "刚果共和国",
|
||||||
|
"Colombia": "哥伦比亚",
|
||||||
|
"Costa Rica": "哥斯达黎加",
|
||||||
|
"Cuba": "古巴",
|
||||||
|
"Northern Cyprus": "北塞浦路斯",
|
||||||
|
"Cyprus": "塞浦路斯",
|
||||||
|
"Czech Republic": "捷克共和国",
|
||||||
|
"Germany": "德国",
|
||||||
|
"Djibouti": "吉布提",
|
||||||
|
"Denmark": "丹麦",
|
||||||
|
"Dominican Republic": "多明尼加共和国",
|
||||||
|
"Algeria": "阿尔及利亚",
|
||||||
|
"Ecuador": "厄瓜多尔",
|
||||||
|
"Egypt": "埃及",
|
||||||
|
"Eritrea": "厄立特里亚",
|
||||||
|
"Spain": "西班牙",
|
||||||
|
"Estonia": "爱沙尼亚",
|
||||||
|
"Ethiopia": "埃塞俄比亚",
|
||||||
|
"Finland": "芬兰",
|
||||||
|
"Fiji": "斐",
|
||||||
|
"Falkland Islands": "福克兰群岛",
|
||||||
|
"France": "法国",
|
||||||
|
"Gabon": "加蓬",
|
||||||
|
"United Kingdom": "英国",
|
||||||
|
"Georgia": "格鲁吉亚",
|
||||||
|
"Ghana": "加纳",
|
||||||
|
"Guinea": "几内亚",
|
||||||
|
"Gambia": "冈比亚",
|
||||||
|
"Guinea Bissau": "几内亚比绍",
|
||||||
|
"Greece": "希腊",
|
||||||
|
"Greenland": "格陵兰",
|
||||||
|
"Guatemala": "危地马拉",
|
||||||
|
"French Guiana": "法属圭亚那",
|
||||||
|
"Guyana": "圭亚那",
|
||||||
|
"Honduras": "洪都拉斯",
|
||||||
|
"Croatia": "克罗地亚",
|
||||||
|
"Haiti": "海地",
|
||||||
|
"Hungary": "匈牙利",
|
||||||
|
"Indonesia": "印度尼西亚",
|
||||||
|
"India": "印度",
|
||||||
|
"Ireland": "爱尔兰",
|
||||||
|
"Iran": "伊朗",
|
||||||
|
"Iraq": "伊拉克",
|
||||||
|
"Iceland": "冰岛",
|
||||||
|
"Israel": "以色列",
|
||||||
|
"Italy": "意大利",
|
||||||
|
"Jamaica": "牙买加",
|
||||||
|
"Jordan": "约旦",
|
||||||
|
"Japan": "日本",
|
||||||
|
"Kazakhstan": "哈萨克斯坦",
|
||||||
|
"Kenya": "肯尼亚",
|
||||||
|
"Kyrgyzstan": "吉尔吉斯斯坦",
|
||||||
|
"Cambodia": "柬埔寨",
|
||||||
|
"Kosovo": "科索沃",
|
||||||
|
"Kuwait": "科威特",
|
||||||
|
"Laos": "老挝",
|
||||||
|
"Lebanon": "黎巴嫩",
|
||||||
|
"Liberia": "利比里亚",
|
||||||
|
"Libya": "利比亚",
|
||||||
|
"Sri Lanka": "斯里兰卡",
|
||||||
|
"Lesotho": "莱索托",
|
||||||
|
"Lithuania": "立陶宛",
|
||||||
|
"Luxembourg": "卢森堡",
|
||||||
|
"Latvia": "拉脱维亚",
|
||||||
|
"Morocco": "摩洛哥",
|
||||||
|
"Moldova": "摩尔多瓦",
|
||||||
|
"Madagascar": "马达加斯加",
|
||||||
|
"Mexico": "墨西哥",
|
||||||
|
"Macedonia": "马其顿",
|
||||||
|
"Mali": "马里",
|
||||||
|
"Myanmar": "缅甸",
|
||||||
|
"Montenegro": "黑山",
|
||||||
|
"Mongolia": "蒙古",
|
||||||
|
"Mozambique": "莫桑比克",
|
||||||
|
"Mauritania": "毛里塔尼亚",
|
||||||
|
"Malawi": "马拉维",
|
||||||
|
"Malaysia": "马来西亚",
|
||||||
|
"Namibia": "纳米比亚",
|
||||||
|
"New Caledonia": "新喀里多尼亚",
|
||||||
|
"Niger": "尼日尔",
|
||||||
|
"Nigeria": "尼日利亚",
|
||||||
|
"Nicaragua": "尼加拉瓜",
|
||||||
|
"Netherlands": "荷兰",
|
||||||
|
"Norway": "挪威",
|
||||||
|
"Nepal": "尼泊尔",
|
||||||
|
"New Zealand": "新西兰",
|
||||||
|
"Oman": "阿曼",
|
||||||
|
"Pakistan": "巴基斯坦",
|
||||||
|
"Panama": "巴拿马",
|
||||||
|
"Peru": "秘鲁",
|
||||||
|
"Philippines": "菲律宾",
|
||||||
|
"Papua New Guinea": "巴布亚新几内亚",
|
||||||
|
"Poland": "波兰",
|
||||||
|
"Puerto Rico": "波多黎各",
|
||||||
|
"North Korea": "北朝鲜",
|
||||||
|
"Portugal": "葡萄牙",
|
||||||
|
"Paraguay": "巴拉圭",
|
||||||
|
"Qatar": "卡塔尔",
|
||||||
|
"Romania": "罗马尼亚",
|
||||||
|
"Russia": "俄罗斯",
|
||||||
|
"Rwanda": "卢旺达",
|
||||||
|
"Western Sahara": "西撒哈拉",
|
||||||
|
"Saudi Arabia": "沙特阿拉伯",
|
||||||
|
"Sudan": "苏丹",
|
||||||
|
"South Sudan": "南苏丹",
|
||||||
|
"Senegal": "塞内加尔",
|
||||||
|
"Solomon Islands": "所罗门群岛",
|
||||||
|
"Sierra Leone": "塞拉利昂",
|
||||||
|
"El Salvador": "萨尔瓦多",
|
||||||
|
"Somaliland": "索马里兰",
|
||||||
|
"Somalia": "索马里",
|
||||||
|
"Republic of Serbia": "塞尔维亚",
|
||||||
|
"Suriname": "苏里南",
|
||||||
|
"Slovakia": "斯洛伐克",
|
||||||
|
"Slovenia": "斯洛文尼亚",
|
||||||
|
"Sweden": "瑞典",
|
||||||
|
"Swaziland": "斯威士兰",
|
||||||
|
"Syria": "叙利亚",
|
||||||
|
"Chad": "乍得",
|
||||||
|
"Togo": "多哥",
|
||||||
|
"Thailand": "泰国",
|
||||||
|
"Tajikistan": "塔吉克斯坦",
|
||||||
|
"Turkmenistan": "土库曼斯坦",
|
||||||
|
"East Timor": "东帝汶",
|
||||||
|
"Trinidad and Tobago": "特里尼达和多巴哥",
|
||||||
|
"Tunisia": "突尼斯",
|
||||||
|
"Turkey": "土耳其",
|
||||||
|
"United Republic of Tanzania": "坦桑尼亚",
|
||||||
|
"Uganda": "乌干达",
|
||||||
|
"Ukraine": "乌克兰",
|
||||||
|
"Uruguay": "乌拉圭",
|
||||||
|
"United States": "美国",
|
||||||
|
"Uzbekistan": "乌兹别克斯坦",
|
||||||
|
"Venezuela": "委内瑞拉",
|
||||||
|
"Vietnam": "越南",
|
||||||
|
"Vanuatu": "瓦努阿图",
|
||||||
|
"West Bank": "西岸",
|
||||||
|
"Yemen": "也门",
|
||||||
|
"South Africa": "南非",
|
||||||
|
"Zambia": "赞比亚",
|
||||||
|
"Korea": "韩国",
|
||||||
|
"Tanzania": "坦桑尼亚",
|
||||||
|
"Zimbabwe": "津巴布韦",
|
||||||
|
"Congo": "刚果",
|
||||||
|
"Central African Rep.": "中非",
|
||||||
|
"Serbia": "塞尔维亚",
|
||||||
|
"Bosnia and Herz.": "波斯尼亚和黑塞哥维那",
|
||||||
|
"Czech Rep.": "捷克",
|
||||||
|
"W. Sahara": "西撒哈拉",
|
||||||
|
"Lao PDR": "老挝",
|
||||||
|
"Dem.Rep.Korea": "朝鲜",
|
||||||
|
"Falkland Is.": "福克兰群岛",
|
||||||
|
"Timor-Leste": "东帝汶",
|
||||||
|
"Solomon Is.": "所罗门群岛",
|
||||||
|
"Palestine": "巴勒斯坦",
|
||||||
|
"N. Cyprus": "北塞浦路斯",
|
||||||
|
"Aland": "奥兰群岛",
|
||||||
|
"Fr. S. Antarctic Lands": "法属南半球和南极陆地",
|
||||||
|
"Mauritius": "毛里求斯",
|
||||||
|
"Comoros": "科摩罗",
|
||||||
|
"Eq. Guinea": "赤道几内亚",
|
||||||
|
"Guinea-Bissau": "几内亚比绍",
|
||||||
|
"Dominican Rep.": "多米尼加",
|
||||||
|
"Saint Lucia": "圣卢西亚",
|
||||||
|
"Dominica": "多米尼克",
|
||||||
|
"Antigua and Barb.": "安提瓜和巴布达",
|
||||||
|
"U.S. Virgin Is.": "美国原始岛屿",
|
||||||
|
"Montserrat": "蒙塞拉特",
|
||||||
|
"Grenada": "格林纳达",
|
||||||
|
"Barbados": "巴巴多斯",
|
||||||
|
"Samoa": "萨摩亚",
|
||||||
|
"Bahamas": "巴哈马",
|
||||||
|
"Cayman Is.": "开曼群岛",
|
||||||
|
"Faeroe Is.": "法罗群岛",
|
||||||
|
"IsIe of Man": "马恩岛",
|
||||||
|
"Malta": "马耳他共和国",
|
||||||
|
"Jersey": "泽西",
|
||||||
|
"Cape Verde": "佛得角共和国",
|
||||||
|
"Turks and Caicos Is.": "特克斯和凯科斯群岛",
|
||||||
|
"St. Vin. and Gren.": "圣文森特和格林纳丁斯",
|
||||||
|
"Singapore Rep.": "新加坡",
|
||||||
|
"Côte d'Ivoire": "科特迪瓦",
|
||||||
|
"Siachen Glacier": "锡亚琴冰川",
|
||||||
|
"Br. Indian Ocean Ter.": "英属印度洋领土",
|
||||||
|
"Dem. Rep. Congo": "刚果民主共和国",
|
||||||
|
"Dem. Rep. Korea": "朝鲜",
|
||||||
|
"S. Sudan": "南苏丹"
|
||||||
|
}
|
1
frontend/src/assets/json/world.json
Normal file
1
frontend/src/assets/json/world.json
Normal file
File diff suppressed because one or more lines are too long
@ -129,32 +129,24 @@
|
|||||||
"type": "cookie",
|
"type": "cookie",
|
||||||
"state": "on",
|
"state": "on",
|
||||||
"code": 403,
|
"code": 403,
|
||||||
"action": "deny",
|
"action": "deny"
|
||||||
"ipBlock": "on",
|
|
||||||
"ipBlockTime": 600
|
|
||||||
},
|
},
|
||||||
"header": {
|
"header": {
|
||||||
"state": "on",
|
"state": "on",
|
||||||
"type": "header",
|
"type": "header",
|
||||||
"code": 403,
|
"code": 403,
|
||||||
"action": "deny",
|
"action": "deny"
|
||||||
"ipBlock": "on",
|
|
||||||
"ipBlockTime": 600
|
|
||||||
},
|
},
|
||||||
"defaultUaBlack": {
|
"defaultUaBlack": {
|
||||||
"type": "defaultUaBlack",
|
"type": "defaultUaBlack",
|
||||||
"state": "on",
|
"state": "on",
|
||||||
"code": 403,
|
"code": 403,
|
||||||
"ipBlock": "on",
|
|
||||||
"ipBlockTime": 600,
|
|
||||||
"action": "deny"
|
"action": "deny"
|
||||||
},
|
},
|
||||||
"args": {
|
"args": {
|
||||||
"type": "args",
|
"type": "args",
|
||||||
"state": "on",
|
"state": "on",
|
||||||
"code": 403,
|
"code": 403,
|
||||||
"action": "deny",
|
"action": "deny"
|
||||||
"ipBlock": "on",
|
|
||||||
"ipBlockTime": 600
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,6 +99,8 @@ local function init_global_config()
|
|||||||
config.html_res = html_res
|
config.html_res = html_res
|
||||||
|
|
||||||
_M.waf_dir = waf_dir
|
_M.waf_dir = waf_dir
|
||||||
|
_M.waf_db_dir = waf_dir .. "db/"
|
||||||
|
_M.waf_db_path = _M.waf_db_dir .. "1pwaf.db"
|
||||||
_M.config_dir = config_dir
|
_M.config_dir = config_dir
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ local function init_dir(path)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function check_table(table_name)
|
local function check_table(table_name,wafdb)
|
||||||
if wafdb == nil then
|
if wafdb == nil then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
@ -35,32 +35,27 @@ function _M.init_db()
|
|||||||
if not ok then
|
if not ok then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
if wafdb then
|
local wafdb
|
||||||
|
init_dir(config.waf_db_dir)
|
||||||
|
wafdb = sqlite3.open(config.waf_db_path)
|
||||||
|
if wafdb == nil then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
local path = config.waf_dir .. "db/"
|
wafdb:exec([[PRAGMA journal_mode = wal]])
|
||||||
init_dir(path)
|
wafdb:exec([[PRAGMA synchronous = 0]])
|
||||||
local db_path = path .. "1pwaf.db"
|
wafdb:exec([[PRAGMA page_size = 8192]])
|
||||||
if wafdb == nil or not wafdb:isopen() then
|
wafdb:exec([[PRAGMA journal_size_limit = 2147483648]])
|
||||||
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 page_size = 8192]])
|
|
||||||
wafdb:exec([[PRAGMA journal_size_limit = 2147483648]])
|
|
||||||
end
|
|
||||||
local status = {}
|
local status = {}
|
||||||
if not check_table("attack_log") then
|
if not check_table("attack_log",wafdb) then
|
||||||
status = wafdb:exec([[
|
status = wafdb:exec([[
|
||||||
CREATE TABLE attack_log (
|
CREATE TABLE attack_log (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id TEXT PRIMARY KEY,
|
||||||
ip TEXT,
|
ip TEXT,
|
||||||
ip_city TEXT,
|
ip_iso TEXT,
|
||||||
ip_country TEXT,
|
ip_country_zh TEXT,
|
||||||
ip_subdivisions TEXT,
|
ip_country_en TEXT,
|
||||||
ip_continent TEXT,
|
ip_province_zh TEXT,
|
||||||
|
ip_province_en TEXT,
|
||||||
ip_longitude TEXT,
|
ip_longitude TEXT,
|
||||||
ip_latitude TEXT,
|
ip_latitude TEXT,
|
||||||
time INTEGER,
|
time INTEGER,
|
||||||
@ -71,16 +66,39 @@ function _M.init_db()
|
|||||||
method TEXT,
|
method TEXT,
|
||||||
uri TEXT,
|
uri TEXT,
|
||||||
user_agent TEXT,
|
user_agent TEXT,
|
||||||
rule TEXT,
|
rule_type TEXT,
|
||||||
|
match_rule TEXT,
|
||||||
|
match_value TEXT,
|
||||||
nginx_log TEXT,
|
nginx_log TEXT,
|
||||||
blocking_time INTEGER,
|
blocking_time INTEGER,
|
||||||
action TEXT,
|
action TEXT,
|
||||||
msg TEXT,
|
|
||||||
params TEXT,
|
|
||||||
is_block INTEGER
|
is_block INTEGER
|
||||||
)]])
|
)]])
|
||||||
|
end
|
||||||
|
|
||||||
ngx.log(ngx.ERR, "init db status" .. status)
|
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
|
||||||
|
status = wafdb:exec([[
|
||||||
|
CREATE TABLE waf_stat (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
day TEXT,
|
||||||
|
req_count INTEGER,
|
||||||
|
attack_count INTEGER,
|
||||||
|
count_4xx INTEGER,
|
||||||
|
count_5xx INTEGER
|
||||||
|
)]])
|
||||||
|
ngx.log(ngx.ERR, "init waf_stat status"..status)
|
||||||
end
|
end
|
||||||
|
|
||||||
ngx.log(ngx.ERR, "init db success")
|
ngx.log(ngx.ERR, "init db success")
|
||||||
|
@ -138,6 +138,7 @@ function _M.exec_action(rule_config, match_rule, data)
|
|||||||
ngx.ctx.rule_table = rule_config
|
ngx.ctx.rule_table = rule_config
|
||||||
ngx.ctx.action = action
|
ngx.ctx.action = action
|
||||||
ngx.ctx.hitData = data
|
ngx.ctx.hitData = data
|
||||||
|
|
||||||
ngx.ctx.isAttack = true
|
ngx.ctx.isAttack = true
|
||||||
|
|
||||||
if rule_config.ipBlock and rule_config.ipBlock == 'on' then
|
if rule_config.ipBlock and rule_config.ipBlock == 'on' then
|
||||||
|
@ -367,8 +367,6 @@ function _M.cc_url()
|
|||||||
local urlcc_config = get_site_config("ccurl")
|
local urlcc_config = get_site_config("ccurl")
|
||||||
local uri = ngx.var.uri
|
local uri = ngx.var.uri
|
||||||
|
|
||||||
ngx.log(ngx.ERR, "ccrules is" .. cjson.encode(urlcc_rules))
|
|
||||||
|
|
||||||
local m, mr = match_rule(urlcc_rules, uri)
|
local m, mr = match_rule(urlcc_rules, uri)
|
||||||
if not m or not mr then
|
if not m or not mr then
|
||||||
return
|
return
|
||||||
|
427
plugins/openresty/waf/lib/resty/uuid.lua
Normal file
427
plugins/openresty/waf/lib/resty/uuid.lua
Normal file
@ -0,0 +1,427 @@
|
|||||||
|
-- vim:set ts=4 sts=4 sw=4 et:
|
||||||
|
|
||||||
|
--- jit-uuid
|
||||||
|
-- Fast and dependency-free UUID library for LuaJIT/ngx_lua.
|
||||||
|
-- @module jit-uuid
|
||||||
|
-- @author Thibault Charbonnier
|
||||||
|
-- @license MIT
|
||||||
|
-- @release 0.0.7
|
||||||
|
|
||||||
|
|
||||||
|
local bit = require 'bit'
|
||||||
|
|
||||||
|
|
||||||
|
local tohex = bit.tohex
|
||||||
|
local band = bit.band
|
||||||
|
local bor = bit.bor
|
||||||
|
|
||||||
|
|
||||||
|
local _M = {
|
||||||
|
_VERSION = '0.0.7'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
----------
|
||||||
|
-- seeding
|
||||||
|
----------
|
||||||
|
|
||||||
|
|
||||||
|
--- Seed the random number generator.
|
||||||
|
-- Under the hood, this function calls `math.randomseed`.
|
||||||
|
-- It makes sure to use the most appropriate seeding technique for
|
||||||
|
-- the current environment, guaranteeing a unique seed.
|
||||||
|
--
|
||||||
|
-- To guarantee unique UUIDs, you must have correctly seeded
|
||||||
|
-- the Lua pseudo-random generator (with `math.randomseed`).
|
||||||
|
-- You are free to seed it any way you want, but this function
|
||||||
|
-- can do it for you if you'd like, with some added guarantees.
|
||||||
|
--
|
||||||
|
-- @param[type=number] seed (Optional) A seed to use. If none given, will
|
||||||
|
-- generate one trying to use the most appropriate technique.
|
||||||
|
-- @treturn number `seed`: the seed given to `math.randomseed`.
|
||||||
|
-- @usage
|
||||||
|
-- local uuid = require 'resty.jit-uuid'
|
||||||
|
-- uuid.seed()
|
||||||
|
--
|
||||||
|
-- -- in ngx_lua, seed in the init_worker context:
|
||||||
|
-- init_worker_by_lua {
|
||||||
|
-- local uuid = require 'resty.jit-uuid'
|
||||||
|
-- uuid.seed()
|
||||||
|
-- }
|
||||||
|
function _M.seed(seed)
|
||||||
|
if not seed then
|
||||||
|
if ngx then
|
||||||
|
seed = ngx.time() + ngx.worker.pid()
|
||||||
|
|
||||||
|
elseif package.loaded['socket'] and package.loaded['socket'].gettime then
|
||||||
|
seed = package.loaded['socket'].gettime()*10000
|
||||||
|
|
||||||
|
else
|
||||||
|
seed = os.time()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
math.randomseed(seed)
|
||||||
|
|
||||||
|
return seed
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-------------
|
||||||
|
-- validation
|
||||||
|
-------------
|
||||||
|
|
||||||
|
|
||||||
|
do
|
||||||
|
if ngx and string.find(ngx.config.nginx_configure(),'--with-pcre-jit',nil,true) then
|
||||||
|
local type = type
|
||||||
|
local re_find = ngx.re.find
|
||||||
|
local regex = '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$'
|
||||||
|
|
||||||
|
|
||||||
|
--- Validate a string as a UUID.
|
||||||
|
-- To be considered valid, a UUID must be given in its canonical
|
||||||
|
-- form (hexadecimal digits including the hyphen characters).
|
||||||
|
-- This function validates UUIDs disregarding their generation algorithm,
|
||||||
|
-- and in a case-insensitive manner, but checks the variant field.
|
||||||
|
--
|
||||||
|
-- Use JIT PCRE if available in OpenResty or fallbacks on Lua patterns.
|
||||||
|
--
|
||||||
|
-- @param[type=string] str String to verify.
|
||||||
|
-- @treturn boolean `valid`: true if valid UUID, false otherwise.
|
||||||
|
-- @usage
|
||||||
|
-- local uuid = require 'resty.jit-uuid'
|
||||||
|
--
|
||||||
|
-- uuid.is_valid 'cbb297c0-a956-486d-ad1d-f9bZZZZZZZZZ' --> false
|
||||||
|
-- uuid.is_valid 'cbb297c0-a956-486d-dd1d-f9b42df9465a' --> false (invalid variant)
|
||||||
|
-- uuid.is_valid 'cbb297c0a956486dad1df9b42df9465a' --> false (no dashes)
|
||||||
|
-- uuid.is_valid 'cbb297c0-a956-486d-ad1d-f9b42df9465a' --> true
|
||||||
|
function _M.is_valid(str)
|
||||||
|
-- it has proven itself efficient to first check the length with an
|
||||||
|
-- evenly distributed set of valid and invalid uuid lengths.
|
||||||
|
if type(str) ~= 'string' or #str ~= 36 then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
return re_find(str, regex, 'ioj') ~= nil
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
local match = string.match
|
||||||
|
local d = '[0-9a-fA-F]'
|
||||||
|
local p = '^' .. table.concat({
|
||||||
|
d:rep(8),
|
||||||
|
d:rep(4),
|
||||||
|
d:rep(4),
|
||||||
|
'[89ab]' .. d:rep(3),
|
||||||
|
d:rep(12)
|
||||||
|
}, '%-') .. '$'
|
||||||
|
|
||||||
|
|
||||||
|
function _M.is_valid(str)
|
||||||
|
if type(str) ~= 'string' or #str ~= 36 then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
return match(str, p) ~= nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
----------------
|
||||||
|
-- v4 generation
|
||||||
|
----------------
|
||||||
|
|
||||||
|
|
||||||
|
do
|
||||||
|
local fmt = string.format
|
||||||
|
local random = math.random
|
||||||
|
|
||||||
|
|
||||||
|
--- Generate a v4 UUID.
|
||||||
|
-- v4 UUIDs are created from randomly generated numbers.
|
||||||
|
--
|
||||||
|
-- @treturn string `uuid`: a v4 (randomly generated) UUID.
|
||||||
|
-- @usage
|
||||||
|
-- local uuid = require 'resty.jit-uuid'
|
||||||
|
--
|
||||||
|
-- local u1 = uuid() ---> __call metamethod
|
||||||
|
-- local u2 = uuid.generate_v4()
|
||||||
|
function _M.generate_v4()
|
||||||
|
return (fmt('%s%s%s%s-%s%s-%s%s-%s%s-%s%s%s%s%s%s',
|
||||||
|
tohex(random(0, 255), 2),
|
||||||
|
tohex(random(0, 255), 2),
|
||||||
|
tohex(random(0, 255), 2),
|
||||||
|
tohex(random(0, 255), 2),
|
||||||
|
|
||||||
|
tohex(random(0, 255), 2),
|
||||||
|
tohex(random(0, 255), 2),
|
||||||
|
|
||||||
|
tohex(bor(band(random(0, 255), 0x0F), 0x40), 2),
|
||||||
|
tohex(random(0, 255), 2),
|
||||||
|
|
||||||
|
tohex(bor(band(random(0, 255), 0x3F), 0x80), 2),
|
||||||
|
tohex(random(0, 255), 2),
|
||||||
|
|
||||||
|
tohex(random(0, 255), 2),
|
||||||
|
tohex(random(0, 255), 2),
|
||||||
|
tohex(random(0, 255), 2),
|
||||||
|
tohex(random(0, 255), 2),
|
||||||
|
tohex(random(0, 255), 2),
|
||||||
|
tohex(random(0, 255), 2)))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
----------------
|
||||||
|
-- v3/v5 generation
|
||||||
|
----------------
|
||||||
|
|
||||||
|
|
||||||
|
do
|
||||||
|
if ngx then
|
||||||
|
local ffi = require 'ffi'
|
||||||
|
|
||||||
|
|
||||||
|
local tonumber = tonumber
|
||||||
|
local assert = assert
|
||||||
|
local error = error
|
||||||
|
local concat = table.concat
|
||||||
|
local type = type
|
||||||
|
local char = string.char
|
||||||
|
local fmt = string.format
|
||||||
|
local sub = string.sub
|
||||||
|
local gmatch = ngx.re.gmatch
|
||||||
|
local sha1_bin = ngx.sha1_bin
|
||||||
|
local md5 = ngx.md5
|
||||||
|
local C = ffi.C
|
||||||
|
local ffi_new = ffi.new
|
||||||
|
local ffi_str = ffi.string
|
||||||
|
local ffi_cast = ffi.cast
|
||||||
|
local new_tab
|
||||||
|
do
|
||||||
|
local ok
|
||||||
|
ok, new_tab = pcall(require, 'table.new')
|
||||||
|
if not ok then
|
||||||
|
new_tab = function(narr, nrec) return {} end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
ffi.cdef [[
|
||||||
|
typedef unsigned char u_char;
|
||||||
|
typedef intptr_t ngx_int_t;
|
||||||
|
|
||||||
|
u_char * ngx_hex_dump(u_char *dst, const u_char *src, size_t len);
|
||||||
|
ngx_int_t ngx_hextoi(u_char *line, size_t n);
|
||||||
|
]]
|
||||||
|
|
||||||
|
|
||||||
|
local str_type = ffi.typeof('uint8_t[?]')
|
||||||
|
local u_char_type = ffi.typeof('u_char *')
|
||||||
|
|
||||||
|
|
||||||
|
local function bin_tohex(s)
|
||||||
|
local slen = #s
|
||||||
|
local blen = slen * 2
|
||||||
|
local buf = ffi_new(str_type, blen)
|
||||||
|
|
||||||
|
C.ngx_hex_dump(buf, s, slen)
|
||||||
|
|
||||||
|
return ffi_str(buf, blen)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function hex_to_i(s)
|
||||||
|
local buf = ffi_cast(u_char_type, s)
|
||||||
|
|
||||||
|
local n = tonumber(C.ngx_hextoi(buf, #s))
|
||||||
|
if n == -1 then
|
||||||
|
error("could not convert hex to number")
|
||||||
|
end
|
||||||
|
|
||||||
|
return n
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local buf = new_tab(16, 0)
|
||||||
|
|
||||||
|
|
||||||
|
local function factory(namespace, hash_fn)
|
||||||
|
if not _M.is_valid(namespace) then
|
||||||
|
return nil, 'namespace must be a valid UUID'
|
||||||
|
end
|
||||||
|
|
||||||
|
local i = 0
|
||||||
|
local iter, err = gmatch(namespace, [[([\da-f][\da-f])]])
|
||||||
|
if not iter then
|
||||||
|
return nil, 'could not create iter: ' .. err
|
||||||
|
end
|
||||||
|
|
||||||
|
while true do
|
||||||
|
local m, err = iter()
|
||||||
|
if err then
|
||||||
|
return nil, err
|
||||||
|
end
|
||||||
|
|
||||||
|
if not m then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
i = i + 1
|
||||||
|
buf[i] = char(tonumber(m[0], 16))
|
||||||
|
end
|
||||||
|
|
||||||
|
assert(i == 16, "invalid binary namespace buffer length")
|
||||||
|
local ns = concat(buf)
|
||||||
|
|
||||||
|
return function(name)
|
||||||
|
if type(name) ~= 'string' then
|
||||||
|
return nil, 'name must be a string'
|
||||||
|
end
|
||||||
|
|
||||||
|
local hash, ver, var = hash_fn(ns, name)
|
||||||
|
|
||||||
|
return (fmt('%s-%s-%s%s-%s%s-%s', sub(hash, 1, 8),
|
||||||
|
sub(hash, 9, 12),
|
||||||
|
ver,
|
||||||
|
sub(hash, 15, 16),
|
||||||
|
var,
|
||||||
|
sub(hash, 19, 20),
|
||||||
|
sub(hash, 21, 32)))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function v3_hash(binary, name)
|
||||||
|
local hash = md5(binary .. name)
|
||||||
|
|
||||||
|
return hash,
|
||||||
|
tohex(bor(band(hex_to_i(sub(hash, 13, 14)), 0x0F), 0x30), 2),
|
||||||
|
tohex(bor(band(hex_to_i(sub(hash, 17, 18)), 0x3F), 0x80), 2)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function v5_hash(binary, name)
|
||||||
|
local hash = bin_tohex(sha1_bin(binary .. name))
|
||||||
|
|
||||||
|
return hash,
|
||||||
|
tohex(bor(band(hex_to_i(sub(hash, 13, 14)), 0x0F), 0x50), 2),
|
||||||
|
tohex(bor(band(hex_to_i(sub(hash, 17, 18)), 0x3F), 0x80), 2)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Instanciate a v3 UUID factory.
|
||||||
|
-- @function factory_v3
|
||||||
|
-- Creates a closure generating namespaced v3 UUIDs.
|
||||||
|
-- @param[type=string] namespace (must be a valid UUID according to `is_valid`)
|
||||||
|
-- @treturn function `factory`: a v3 UUID generator.
|
||||||
|
-- @treturn string `err`: a string describing an error
|
||||||
|
-- @usage
|
||||||
|
-- local uuid = require 'resty.jit-uuid'
|
||||||
|
--
|
||||||
|
-- local fact = assert(uuid.factory_v3('e6ebd542-06ae-11e6-8e82-bba81706b27d'))
|
||||||
|
--
|
||||||
|
-- local u1 = fact('hello')
|
||||||
|
-- ---> 3db7a435-8c56-359d-a563-1b69e6802c78
|
||||||
|
--
|
||||||
|
-- local u2 = fact('foobar')
|
||||||
|
-- ---> e8d3eeba-7723-3b72-bbc5-8f598afa6773
|
||||||
|
function _M.factory_v3(namespace)
|
||||||
|
return factory(namespace, v3_hash)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Instanciate a v5 UUID factory.
|
||||||
|
-- @function factory_v5
|
||||||
|
-- Creates a closure generating namespaced v5 UUIDs.
|
||||||
|
-- @param[type=string] namespace (must be a valid UUID according to `is_valid`)
|
||||||
|
-- @treturn function `factory`: a v5 UUID generator.
|
||||||
|
-- @treturn string `err`: a string describing an error
|
||||||
|
-- @usage
|
||||||
|
-- local uuid = require 'resty.jit-uuid'
|
||||||
|
--
|
||||||
|
-- local fact = assert(uuid.factory_v5('e6ebd542-06ae-11e6-8e82-bba81706b27d'))
|
||||||
|
--
|
||||||
|
-- local u1 = fact('hello')
|
||||||
|
-- ---> 4850816f-1658-5890-8bfd-1ed14251f1f0
|
||||||
|
--
|
||||||
|
-- local u2 = fact('foobar')
|
||||||
|
-- ---> c9be99fc-326b-5066-bdba-dcd31a6d01ab
|
||||||
|
function _M.factory_v5(namespace)
|
||||||
|
return factory(namespace, v5_hash)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Generate a v3 UUID.
|
||||||
|
-- v3 UUIDs are created from a namespace and a name (a UUID and a string).
|
||||||
|
-- The same name and namespace result in the same UUID. The same name and
|
||||||
|
-- different namespaces result in different UUIDs, and vice-versa.
|
||||||
|
-- The resulting UUID is derived using MD5 hashing.
|
||||||
|
--
|
||||||
|
-- This is a sugar function which instanciates a short-lived v3 UUID factory.
|
||||||
|
-- It is an expensive operation, and intensive generation using the same
|
||||||
|
-- namespaces should prefer allocating their own long-lived factory with
|
||||||
|
-- `factory_v3`.
|
||||||
|
--
|
||||||
|
-- @param[type=string] namespace (must be a valid UUID according to `is_valid`)
|
||||||
|
-- @param[type=string] name
|
||||||
|
-- @treturn string `uuid`: a v3 (namespaced) UUID.
|
||||||
|
-- @treturn string `err`: a string describing an error
|
||||||
|
-- @usage
|
||||||
|
-- local uuid = require 'resty.jit-uuid'
|
||||||
|
--
|
||||||
|
-- local u = uuid.generate_v3('e6ebd542-06ae-11e6-8e82-bba81706b27d', 'hello')
|
||||||
|
-- ---> 3db7a435-8c56-359d-a563-1b69e6802c78
|
||||||
|
function _M.generate_v3(namespace, name)
|
||||||
|
local fact, err = _M.factory_v3(namespace)
|
||||||
|
if not fact then
|
||||||
|
return nil, err
|
||||||
|
end
|
||||||
|
|
||||||
|
return fact(name)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Generate a v5 UUID.
|
||||||
|
-- v5 UUIDs are created from a namespace and a name (a UUID and a string).
|
||||||
|
-- The same name and namespace result in the same UUID. The same name and
|
||||||
|
-- different namespaces result in different UUIDs, and vice-versa.
|
||||||
|
-- The resulting UUID is derived using SHA-1 hashing.
|
||||||
|
--
|
||||||
|
-- This is a sugar function which instanciates a short-lived v5 UUID factory.
|
||||||
|
-- It is an expensive operation, and intensive generation using the same
|
||||||
|
-- namespaces should prefer allocating their own long-lived factory with
|
||||||
|
-- `factory_v5`.
|
||||||
|
--
|
||||||
|
-- @param[type=string] namespace (must be a valid UUID according to `is_valid`)
|
||||||
|
-- @param[type=string] name
|
||||||
|
-- @treturn string `uuid`: a v5 (namespaced) UUID.
|
||||||
|
-- @treturn string `err`: a string describing an error
|
||||||
|
-- @usage
|
||||||
|
-- local uuid = require 'resty.jit-uuid'
|
||||||
|
--
|
||||||
|
-- local u = uuid.generate_v5('e6ebd542-06ae-11e6-8e82-bba81706b27d', 'hello')
|
||||||
|
-- ---> 4850816f-1658-5890-8bfd-1ed14251f1f0
|
||||||
|
function _M.generate_v5(namespace, name)
|
||||||
|
local fact, err = _M.factory_v5(namespace)
|
||||||
|
if not fact then
|
||||||
|
return nil, err
|
||||||
|
end
|
||||||
|
|
||||||
|
return fact(name)
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
function _M.factory_v3() error('v3 UUID generation only supported in ngx_lua', 2) end
|
||||||
|
function _M.generate_v3() error('v3 UUID generation only supported in ngx_lua', 2) end
|
||||||
|
function _M.factory_v5() error('v5 UUID generation only supported in ngx_lua', 2) end
|
||||||
|
function _M.generate_v5() error('v5 UUID generation only supported in ngx_lua', 2) end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
return setmetatable(_M, {
|
||||||
|
__call = _M.generate_v4
|
||||||
|
})
|
@ -5,6 +5,11 @@ local tonumber = tonumber
|
|||||||
local ipairs = ipairs
|
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 gsub_str = string.gsub
|
||||||
|
local format_str = string.format
|
||||||
|
local random = math.random
|
||||||
|
|
||||||
|
|
||||||
local _M = {}
|
local _M = {}
|
||||||
|
|
||||||
@ -120,4 +125,47 @@ end
|
|||||||
function _M.get_headers()
|
function _M.get_headers()
|
||||||
return ngx.req.get_headers(20000)
|
return ngx.req.get_headers(20000)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function _M.is_intranet_address(ip_addr)
|
||||||
|
if not ip_addr then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
if ip_addr == "unknown" then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
if find_str(ip_addr, ':') then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local parts = {}
|
||||||
|
for part in gmatch_str(ip_addr, "%d+") do
|
||||||
|
insert_table(parts, tonumber(part))
|
||||||
|
end
|
||||||
|
if parts[1] == 10 or
|
||||||
|
(parts[1] == 192 and parts[2] == 168) or
|
||||||
|
(parts[1] == 172 and parts[2] >= 16 and parts[2] <= 31) then
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function _M.uuid()
|
||||||
|
local template ='xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'
|
||||||
|
return gsub_str(template, '[xy]', function (c)
|
||||||
|
local v = (c == 'x') and random(0, 0xf) or random(8, 0xb)
|
||||||
|
return format_str('%x', v)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
function _M.get_wafdb(waf_db_path)
|
||||||
|
local ok, sqlite3 = pcall(function()
|
||||||
|
return require "lsqlite3"
|
||||||
|
end)
|
||||||
|
if not ok then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
return sqlite3.open(waf_db_path)
|
||||||
|
end
|
||||||
return _M
|
return _M
|
||||||
|
@ -1,24 +1,16 @@
|
|||||||
local utils = require "utils"
|
local utils = require "utils"
|
||||||
local stringutf8 = require "stringutf8"
|
|
||||||
local logger_factory = require "logger_factory"
|
|
||||||
local db = require "db"
|
|
||||||
local config = require "config"
|
local config = require "config"
|
||||||
local redis_util = require "redis_util"
|
local redis_util = require "redis_util"
|
||||||
local action = require "action"
|
local action = require "action"
|
||||||
|
local uuid = require"resty.uuid"
|
||||||
|
|
||||||
local upper_str = string.upper
|
local upper_str = string.upper
|
||||||
local concat_table = table.concat
|
|
||||||
local tonumber = tonumber
|
local tonumber = tonumber
|
||||||
local get_expire_time = utils.get_expire_time
|
local pairs = pairs
|
||||||
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 function writeAttackLog()
|
||||||
local rule_table = ngx.ctx.rule_table
|
local rule_table = ngx.ctx.rule_table
|
||||||
local data = ngx.ctx.hitData
|
|
||||||
local action = ngx.ctx.action
|
local action = ngx.ctx.action
|
||||||
local rule = rule_table.rule
|
local rule = rule_table.rule
|
||||||
|
|
||||||
@ -27,38 +19,41 @@ local function writeAttackLog()
|
|||||||
rule_type = "default"
|
rule_type = "default"
|
||||||
end
|
end
|
||||||
|
|
||||||
local realIp = ngx.ctx.ip
|
local real_ip = ngx.ctx.ip
|
||||||
|
|
||||||
local geoip = ngx.ctx.geoip
|
local geoip = ngx.ctx.geoip
|
||||||
local country = geoip.country["zh"] or ""
|
local country = geoip.country
|
||||||
local province = geoip.province["zh"] or ""
|
if not country then
|
||||||
local city = ""
|
country["zh"] = "unknown"
|
||||||
|
country["en"] = "unknown"
|
||||||
|
end
|
||||||
|
local province = geoip.province
|
||||||
|
if not province then
|
||||||
|
province["zh"] = "unknown"
|
||||||
|
province["en"] = "unknown"
|
||||||
|
end
|
||||||
local longitude = geoip.longitude
|
local longitude = geoip.longitude
|
||||||
local latitude = geoip.latitude
|
local latitude = geoip.latitude
|
||||||
|
local iso = geoip.iso
|
||||||
|
|
||||||
local method = ngx.req.get_method()
|
local method = ngx.req.get_method()
|
||||||
local uri = ngx.var.request_uri
|
local uri = ngx.var.request_uri
|
||||||
local ua = ngx.ctx.ua
|
local ua = ngx.ctx.ua
|
||||||
local host = ngx.var.server_name
|
local host = ngx.var.server_name
|
||||||
local protocol = ngx.var.server_protocol
|
local protocol = ngx.var.server_protocol
|
||||||
local attackTime = ngx.localtime()
|
|
||||||
|
|
||||||
local website_key = ngx.ctx.website_key
|
local website_key = ngx.ctx.website_key
|
||||||
|
|
||||||
|
|
||||||
local address = country .. province .. city
|
|
||||||
address = stringutf8.default_if_blank(address, '-')
|
local logs_str = method .. " " .. uri .. " "..protocol.."\n"
|
||||||
ua = stringutf8.default_if_blank(ua, '-')
|
local headers = ngx.req.get_headers(20000)
|
||||||
data = stringutf8.default_if_blank(data, '-')
|
for k, v in pairs(headers) do
|
||||||
|
local value = ""
|
||||||
local log_path = "/www/sites/" .. website_key .. "/attack.log"
|
if v then
|
||||||
local logStr = concat_table({ rule_type, realIp, address, "[" .. attackTime .. "]", '"' .. method, host, uri, protocol .. '"', data, '"' .. ua .. '"', '"' .. rule .. '"', action }, ' ')
|
value = v
|
||||||
local host_logger = logger_factory.get_logger(log_path, host, true)
|
end
|
||||||
host_logger:log(logStr .. '\n')
|
logs_str = logs_str .. upper_str(k) .. ": " .. value .. "\n"
|
||||||
|
|
||||||
db.init_db()
|
|
||||||
if wafdb == nil then
|
|
||||||
return false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local isBlock = 0
|
local isBlock = 0
|
||||||
local blocking_time = 0
|
local blocking_time = 0
|
||||||
@ -67,43 +62,58 @@ local function writeAttackLog()
|
|||||||
blocking_time = tonumber(rule_table.ipBlockTime)
|
blocking_time = tonumber(rule_table.ipBlockTime)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local log_id = uuid()
|
||||||
|
local time = os.time()
|
||||||
|
local localtime = os.date("%Y-%m-%d %H:%M:%S", time)
|
||||||
|
|
||||||
|
|
||||||
|
local wafdb = utils.get_wafdb(config.waf_db_path)
|
||||||
|
if wafdb == nil then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
local insertQuery = [[
|
local insertQuery = [[
|
||||||
INSERT INTO attack_log (
|
INSERT INTO attack_log (
|
||||||
ip, ip_city, ip_country, ip_subdivisions, ip_continent,
|
id, ip, ip_iso, ip_country_zh, ip_country_en,
|
||||||
ip_longitude, ip_latitude, time, localtime, server_name,
|
ip_province_zh, ip_province_en, ip_longitude, ip_latitude,
|
||||||
website_key, host, method, uri, user_agent, rule,
|
time, localtime, server_name, website_key, host, method,
|
||||||
nginx_log, blocking_time, action, msg, params, is_block
|
uri, user_agent, rule_type,match_rule, match_value,
|
||||||
|
nginx_log, blocking_time, action, is_block
|
||||||
) VALUES (
|
) VALUES (
|
||||||
:realIp, :city, :country, :subdivisions, :continent,
|
:id, :real_ip, :iso, :country_zh, :country_en,
|
||||||
:longitude, :latitude, :time, :localtime, :host,
|
:province_zh, :province_en,:longitude, :latitude,
|
||||||
:website_key, :host, :method, :uri, :ua, :rule_type,
|
:time, :localtime, :server_name,:host, :website_key, :method,
|
||||||
:logStr, :blocking_time, :action, :msg, :params, :is_block
|
:uri, :ua, :rule_type, :match_rule, :match_value,
|
||||||
|
:logs_str, :blocking_time, :action, :is_block
|
||||||
)
|
)
|
||||||
]]
|
]]
|
||||||
|
|
||||||
local stmt = wafdb:prepare(insertQuery)
|
local stmt = wafdb:prepare(insertQuery)
|
||||||
|
|
||||||
stmt:bind_names {
|
stmt:bind_names {
|
||||||
realIp = realIp,
|
id = log_id,
|
||||||
city = city,
|
iso = iso,
|
||||||
country = country,
|
real_ip = real_ip,
|
||||||
subdivisions = "",
|
country_zh = country["zh"],
|
||||||
continent = "",
|
country_en = country["en"],
|
||||||
|
province_zh = province["zh"],
|
||||||
|
province_en = province["en"],
|
||||||
longitude = longitude,
|
longitude = longitude,
|
||||||
latitude = latitude,
|
latitude = latitude,
|
||||||
time = os.time(),
|
time = time,
|
||||||
localtime = os.date("%Y-%m-%d %H:%M:%S", os.time()),
|
localtime = localtime,
|
||||||
host = host,
|
host = 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,
|
rule_type = rule_type,
|
||||||
logStr = logStr,
|
match_rule = rule,
|
||||||
|
match_value = "",
|
||||||
|
logs_str = logs_str,
|
||||||
blocking_time = blocking_time or 0,
|
blocking_time = blocking_time or 0,
|
||||||
action = action,
|
action = action,
|
||||||
msg = "msg",
|
|
||||||
params = "Params",
|
|
||||||
is_block = isBlock
|
is_block = isBlock
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,77 +123,12 @@ local function writeAttackLog()
|
|||||||
if code ~= 101 then
|
if code ~= 101 then
|
||||||
local errorMsg = wafdb:errmsg()
|
local errorMsg = wafdb:errmsg()
|
||||||
if errorMsg then
|
if errorMsg then
|
||||||
ngx.log(ngx.ERR, "insert attack_log error", errorMsg)
|
ngx.log(ngx.ERR, "insert attack_log error ", errorMsg .. " ")
|
||||||
end
|
end
|
||||||
end
|
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
|
|
||||||
|
|
||||||
--[[
|
|
||||||
按小时统计当天攻击请求流量,存入缓存,key格式:attack_2023-05-05 09
|
|
||||||
按天统计当天所有攻击类型流量,存入缓存,key格式:attack_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()
|
local function count_not_found()
|
||||||
if ngx.status ~= 404 then
|
if ngx.status ~= 404 then
|
||||||
return
|
return
|
||||||
@ -218,15 +163,9 @@ end
|
|||||||
|
|
||||||
if config.is_waf_on() then
|
if config.is_waf_on() then
|
||||||
count_not_found()
|
count_not_found()
|
||||||
countRequestTraffic()
|
|
||||||
local isAttack = ngx.ctx.isAttack
|
local isAttack = ngx.ctx.isAttack
|
||||||
|
|
||||||
if isAttack then
|
if isAttack then
|
||||||
writeAttackLog()
|
writeAttackLog()
|
||||||
countAttackRequestTraffic()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- if ngx.ctx.ipBlocked then
|
|
||||||
-- writeIPBlockLog()
|
|
||||||
-- end
|
|
||||||
end
|
end
|
||||||
|
@ -37,11 +37,26 @@ local function get_website_key()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
if s_name == '_' then
|
if s_name == '_' then
|
||||||
s_name = "UNKNOWN"
|
s_name = "unknown"
|
||||||
end
|
end
|
||||||
return s_name
|
return s_name
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function get_geo_ip(ip)
|
||||||
|
if utils.is_intranet_address(ip) then
|
||||||
|
return {
|
||||||
|
country = { ["zh"] = "内网", ["en"] = "intranet" },
|
||||||
|
province = { ["zh"] = "内网", ["en"] = "intranet" },
|
||||||
|
city = { ["zh"] = "内网", ["en"] = "intranet" },
|
||||||
|
longitude = 0,
|
||||||
|
latitude = 0,
|
||||||
|
iso = "local"
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return geoip.lookup(ip)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local function init()
|
local function init()
|
||||||
local ip = utils.get_real_ip()
|
local ip = utils.get_real_ip()
|
||||||
ngx.ctx.ip = ip
|
ngx.ctx.ip = ip
|
||||||
@ -52,7 +67,7 @@ local function init()
|
|||||||
ngx.ctx.ua = ua
|
ngx.ctx.ua = ua
|
||||||
geoip.init()
|
geoip.init()
|
||||||
|
|
||||||
ngx.ctx.geoip = geoip.lookup(ip)
|
ngx.ctx.geoip = get_geo_ip(ip)
|
||||||
|
|
||||||
local msg = "访问 IP " .. ip
|
local msg = "访问 IP " .. ip
|
||||||
if ngx.ctx.geoip.country then
|
if ngx.ctx.geoip.country then
|
||||||
|
2
plugins/openresty/waf/worker.lua
Normal file
2
plugins/openresty/waf/worker.lua
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
local uuid = require 'resty.uuid'
|
||||||
|
uuid.seed()
|
Loading…
x
Reference in New Issue
Block a user