-
Notifications
You must be signed in to change notification settings - Fork 44
/
config.lua
384 lines (323 loc) · 12.7 KB
/
config.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
-- Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
-- Copyright (c) 2023 bukale [email protected]
local cjson = require "cjson"
local file_utils = require "file_utils"
local ip_utils = require "ip_utils"
local constants = require "constants"
local stringutf8 = require "stringutf8"
local nkeys = require "table.nkeys"
local ffi = require "ffi"
local ipmatcher = require "resty.ipmatcher"
local read_rule = file_utils.read_rule
local read_file_to_string = file_utils.read_file_to_string
local read_file_to_table = file_utils.read_file_to_table
local write_string_to_file = file_utils.write_string_to_file
local is_file_exists = file_utils.is_file_exists
local is_directory = file_utils.is_directory
local mkdir = file_utils.mkdir
local sub = string.sub
local default_if_blank = stringutf8.default_if_blank
local cjson_decode = cjson.decode
local cjson_encode = cjson.encode
local pairs = pairs
local ipairs = ipairs
local tonumber = tonumber
local _M = {}
local config = {system = {}, global = {}}
_M.ipgroups = {}
-- Returns true if the global config option is "on",otherwise false
function _M.is_global_option_on(option)
return config.global.config[option].state == "on"
end
function _M.is_system_option_on(option)
return config.system[option].state == "on"
end
function _M.is_site_option_on(option)
local server_name = ngx.ctx.server_name or default_if_blank(ngx.var.server_name, 'unknown')
if not config[server_name] then
return _M.is_global_option_on(option)
end
return config[server_name].config[option].state == "on"
end
function _M.get_system_config(option)
if option then
return config.system[option]
end
return config.system
end
function _M.get_global_config(option)
if option then
return config.global.config[option]
end
return config.global.config
end
function _M.get_site_config(option)
local server_name = ngx.ctx.server_name or default_if_blank(ngx.var.server_name, 'unknown')
if not config[server_name] then
return _M.get_global_config(option)
end
if option then
return config[server_name].config[option]
end
return config[server_name].config
end
function _M.get_global_security_modules(module)
if module then
return config.global.security_modules[module]
end
return config.global.security_modules
end
function _M.get_site_security_modules(module)
local server_name = ngx.ctx.server_name or default_if_blank(ngx.var.server_name, 'unknown')
if not config[server_name] then
return _M.get_global_security_modules(module)
end
if module then
return config[server_name].security_modules[module]
end
return config[server_name].security_modules
end
function _M.get_site_config_file(site_id)
local config_file = ''
if site_id == '0' then
config_file = _M.CONF_PATH .. '/global.json'
else
config_file = _M.CONF_PATH .. '/sites/' .. site_id .. '/config.json'
if not is_file_exists(config_file) then
config_file = _M.CONF_PATH .. '/global.json'
end
end
return config_file, read_file_to_string(config_file)
end
function _M.update_site_config_file(site_id, str)
local config_file = ''
if site_id == '0' then
config_file = _M.CONF_PATH .. '/global.json'
else
local site_dir = _M.CONF_PATH .. '/sites/' .. site_id
config_file = site_dir .. '/config.json'
if not is_directory(site_dir) then
mkdir(site_dir)
end
end
return write_string_to_file(config_file, str)
end
function _M.get_site_module_rule_file(site_id, module_id)
local file_name = module_id .. '.json'
local rule_file = ''
if site_id == '0' then
rule_file = _M.CONF_PATH .. '/global_rules/' .. file_name
else
rule_file = _M.CONF_PATH .. '/sites/' .. site_id .. '/rules/' .. file_name
if not is_file_exists(rule_file) then
rule_file = _M.CONF_PATH .. '/global_rules/' .. file_name
end
end
return rule_file, read_file_to_string(rule_file)
end
function _M.update_site_module_rule_file(site_id, module_id, str)
local file_name = module_id .. '.json'
local rule_file = ''
if site_id == '0' then
rule_file = _M.CONF_PATH .. '/global_rules/' .. file_name
else
local site_dir = _M.CONF_PATH .. '/sites/' .. site_id
if not is_directory(site_dir) then
mkdir(site_dir)
end
local rules_dir = site_dir .. '/rules'
if not is_directory(rules_dir) then
mkdir(rules_dir)
end
rule_file = rules_dir .. '/' .. file_name
end
return write_string_to_file(rule_file, str)
end
local function add_ip_group(group, ips)
if ips and nkeys(ips) > 0 then
local matcher, err = ipmatcher.new(ips)
if not matcher then
ngx.log(ngx.ERR, 'error to add ip group ' .. group, err)
return
end
_M.ipgroups[group] = matcher
end
end
function _M.get_config_table()
return config
end
local function load_security_modules(rulePath, site_config)
local security_modules = {}
security_modules.blackUrl = read_rule(rulePath, "blackUrl")
security_modules.args = read_rule(rulePath, "args")
security_modules.whiteUrl = read_rule(rulePath, "whiteUrl")
security_modules.post = read_rule(rulePath, "post")
security_modules.cookie = read_rule(rulePath, "cookie")
security_modules.headers = read_rule(rulePath, "headers")
security_modules.httpMethod = read_rule(rulePath, "httpMethod")
security_modules.fileExt = read_rule(rulePath, "fileExt")
security_modules.cc = read_rule(rulePath, "cc")
security_modules.acl = read_rule(rulePath, "acl")
security_modules.sensitive = read_rule(rulePath, "sensitive")
security_modules["user-agent"] = read_rule(rulePath, "user-agent")
security_modules.sqli = { moduleName = "SQL注入检测", rules = {{ attackType = "sqli", rule = "sqli", action = "DENY", severityLevel="high" }}}
security_modules.xss = { moduleName = "XSS检测", rules = {{ attackType = "xss", rule = "xss", action = "DENY", severityLevel="low" }}}
security_modules.whiteIp = { moduleName = "IP白名单检测", rules = {{ attackType = "whiteip", rule = "whiteip", action = "ALLOW", severityLevel="low" }}}
security_modules.blackIp = { moduleName = "IP黑名单检测", rules = {{ attackType = "blackip", rule = "blackip", action = "REDIRECT", severityLevel="high" }}}
local trap = site_config.bot.trap
local rule_trap = { attackType = "bot_trap", rule = "bot_trap", severityLevel="low" }
rule_trap.action = trap.action
rule_trap.autoIpBlock = trap.autoIpBlock
rule_trap.ipBlockExpireInSeconds = tonumber(trap.ipBlockExpireInSeconds)
rule_trap.uri = trap.uri
security_modules.botTrap = { moduleName = "Bot识别", rules = {rule_trap}}
local captcha = site_config.bot.captcha
local rule_captcha = { attackType = "captcha", rule = "captcha", severityLevel="low" }
rule_captcha.action = captcha.action
rule_captcha.autoIpBlock = captcha.autoIpBlock
rule_captcha.ipBlockExpireInSeconds = tonumber(captcha.ipBlockExpireInSeconds)
rule_captcha.verifyInSeconds = tonumber(captcha.verifyInSeconds)
rule_captcha.maxFailTimes = tonumber(captcha.maxFailTimes)
rule_captcha.expireInSeconds = tonumber(captcha.expireInSeconds)
rule_captcha.type = captcha.type
security_modules.captcha = { moduleName = "人机验证", rules = {rule_captcha}}
return security_modules
end
local function storage_security_modules(server_name, security_modules)
local json = cjson_encode(security_modules)
local dict_config = ngx.shared.dict_config
dict_config:set(server_name, json)
end
local function load_system_config()
local system_path = _M.CONF_PATH .. '/system.json'
local json = read_file_to_string(system_path)
local system = {}
if json then
system = cjson_decode(json)
end
local log_path = system.attackLog.logPath
if log_path and #log_path > 0 then
local last = sub(log_path, -1)
if last ~= "/" and last ~= "\\" then
log_path = log_path .. "/"
end
end
_M.LOG_PATH = log_path or _M.ZHONGKUI_PATH .. "/logs/hack/"
system.attackLog.logPath = _M.LOG_PATH
system.html = read_file_to_string(_M.ZHONGKUI_PATH .. "/html/redirect.html")
system.challenge_html = read_file_to_string(_M.ZHONGKUI_PATH .. "/html/challenge.html")
config.system = system
end
local function load_global_config()
local global_path = _M.CONF_PATH .. '/global.json'
local global_config = {}
local security_modules = {}
local json = read_file_to_string(global_path)
if json then
global_config = cjson_decode(json)
if global_config.waf.state == 'on' then
security_modules = load_security_modules(_M.CONF_PATH .. '/global_rules/', global_config)
storage_security_modules('global', security_modules)
end
end
config.global = {config = global_config, security_modules = security_modules}
local ip_blacklist = read_file_to_table(_M.CONF_PATH .. "/global_rules/ipBlackList")
local ip_whitelist = read_file_to_table(_M.CONF_PATH .. "/global_rules/ipWhiteList")
add_ip_group(constants.KEY_IP_GROUPS_BLACKLIST, ip_blacklist)
add_ip_group(constants.KEY_IP_GROUPS_WHITELIST, ip_whitelist)
end
local function load_site_config()
local website_path = _M.CONF_PATH .. '/website.json'
local json = read_file_to_string(website_path)
if json then
local global = config.global
local global_config = global.config
local t = cjson_decode(json)
local sites = t.rules
if sites then
for _, site in pairs(sites) do
local site_config = {}
local id = site.id
local site_dir = _M.CONF_PATH .. '/sites/' .. tostring(id)
local config_file = site_dir .. '/config.json'
local config_str = read_file_to_string(config_file)
if config_str then
site_config = cjson_decode(config_str)
end
-- 站点有独立设置则使用独立设置,否则使用全局设置
for k, v in pairs(global_config) do
site_config[k] = site_config[k] or v
end
-- waf全局关闭则关闭站点waf
if global_config.waf.state == 'off' then
site_config.waf.state = 'off'
end
local security_modules = load_security_modules(site_dir .. '/rules/', site_config)
-- 站点有独立安全模块设置则使用独立设置,否则使用全局设置
for k, v in pairs(global.security_modules) do
security_modules[k] = security_modules[k] or v
end
local serverNames = site.serverNames
for _, server_name in pairs(serverNames) do
config[server_name] = {config = site_config, security_modules = security_modules}
storage_security_modules(server_name, security_modules)
end
end
end
end
end
local function load_ip_groups()
local path = _M.CONF_PATH .. '/ipgroup.json'
local json = read_file_to_string(path)
if json then
local table_rule = cjson_decode(json)
local groups = table_rule.rules
if groups then
for _, g in pairs(groups) do
add_ip_group(tonumber(g.id), g.ips)
end
end
end
end
-- 加载配置文件
function _M.load_config_file()
load_system_config()
load_global_config()
load_site_config()
load_ip_groups()
end
-- 获取nginx安装目录
local function get_nginx_command_path()
local path = ''
-- 获取当前 Lua 脚本的文件路径
local script_path = debug.getinfo(1, "S").source:sub(2)
-- 获取 OpenResty 安装目录(假设 OpenResty 在 "/usr/local/openresty" 目录下)
local openresty_path = script_path:match("(.*/openresty/)")
if openresty_path then
path = openresty_path .. 'nginx/sbin/'
end
return path
end
-- 是否Linux系统
local function is_linux()
return ffi.os == "Linux"
end
-- 重新加载nginx配置
function _M.reload_nginx()
-- Nginx重新加载配置文件的系统命令
local command = get_nginx_command_path() .. "nginx -s reload"
if is_linux() then
command = "sudo " .. command
end
local success = os.execute(command)
if success then
ngx.log(ngx.INFO, "nginx configuration has been successfully reloaded.")
else
ngx.log(ngx.ERR, "failed to reload Nginx configuration.")
end
end
-- 如果配置文件正确,则重载nginx
function _M.reload_config_file()
_M.reload_nginx()
end
return _M