pull/216/head
midoks 3 years ago
parent 63e6a95553
commit e289037598
  1. 1
      plugins/op_waf/conf/init.sql
  2. 18
      plugins/op_waf/index.html
  3. 87
      plugins/op_waf/index.py
  4. 214
      plugins/op_waf/js/op_waf.js
  5. 6
      plugins/op_waf/t/index.py
  6. 9
      plugins/op_waf/waf/lua/common.lua
  7. 1
      plugins/op_waf/waf/lua/init.lua
  8. 2
      plugins/webstats/js/stats.js

@ -10,6 +10,7 @@ CREATE TABLE IF NOT EXISTS `logs` (
`server_name` TEXT, `server_name` TEXT,
`method` TEXT, `method` TEXT,
`status_code` INTEGER, `status_code` INTEGER,
`user_agent` TEXT,
`uri` TEXT, `uri` TEXT,
`rule_name` TEXT, `rule_name` TEXT,
`reason` TEXT `reason` TEXT

@ -1,4 +1,18 @@
<style> <style>
.overflow_hide {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: inline-block;
vertical-align: middle;
}
.cur {
background-color: #20a53a;
color: #fff;
}
/*waf*/ /*waf*/
.lib-con-title { .lib-con-title {
height: 26px; height: 26px;
@ -231,8 +245,8 @@
<p onclick="wafScreen();">首页</p> <p onclick="wafScreen();">首页</p>
<p onclick="wafGloabl();">全局配置</p> <p onclick="wafGloabl();">全局配置</p>
<p onclick="wafSite();">站点配置</p> <p onclick="wafSite();">站点配置</p>
<p onclick="wafHistory();">封锁历史</p> <p onclick="wafLogs();">封锁历史</p>
<p onclick="wafLogs();">操作日志</p> <p onclick="wafOpLogs();">操作日志</p>
</div> </div>
<!-- lib-con --> <!-- lib-con -->
<div class="bt-w-con pd15"> <div class="bt-w-con pd15">

@ -291,6 +291,29 @@ def autoMakeLuaConf():
autoMakeLuaHtmlSingle(x) autoMakeLuaHtmlSingle(x)
def initDefaultInfo():
path = getServerDir()
djson = path + "/waf/domains.json"
default_json = path + "/waf/default.json"
if os.path.exists(djson):
content = mw.readFile(djson)
content = json.loads(content)
ddata = {}
dlist = []
for i in content:
dlist.append(i["name"])
dlist.append('unset')
ddata["list"] = dlist
if len(ddata["list"]) < 1:
ddata["default"] = "unset"
else:
ddata["default"] = dlist[0]
mw.writeFile(default_json, json.dumps(ddata))
def initDreplace(): def initDreplace():
path = getServerDir() path = getServerDir()
@ -341,6 +364,8 @@ def initDreplace():
initTotalInfo() initTotalInfo()
autoMakeLuaConf() autoMakeLuaConf()
initDefaultInfo()
pSqliteDb() pSqliteDb()
if not mw.isAppleSystem(): if not mw.isAppleSystem():
@ -881,6 +906,26 @@ def getSiteConfig():
return mw.returnJson(True, 'ok!', content) return mw.returnJson(True, 'ok!', content)
def getSiteListData():
path = getServerDir() + "/waf/default.json"
data = mw.readFile(path)
return json.loads(data)
def setDefaultSite(name):
path = getServerDir() + "/waf/default.json"
data = mw.readFile(path)
data = json.loads(data)
data['default'] = name
mw.writeFile(path, json.dumps(data))
return mw.returnJson(True, 'OK')
def getDefaultSite():
data = getSiteListData()
return mw.returnJson(True, 'OK', data)
def getSiteConfigByName(): def getSiteConfigByName():
args = getArgs() args = getArgs()
data = checkArgs(args, ['siteName']) data = checkArgs(args, ['siteName'])
@ -963,24 +1008,38 @@ def importData():
def getLogsList(): def getLogsList():
args = getArgs() args = getArgs()
data = checkArgs(args, ['siteName']) data = checkArgs(args, ['site', 'page', 'page_size', 'tojs'])
if not data[0]: if not data[0]:
return data[1] return data[1]
data = [] page = int(args['page'])
path = getServerDir() + '/logs' page_size = int(args['page_size'])
domain = args['site']
tojs = args['tojs']
if not os.path.exists(path): conn = pSqliteDb('logs')
return mw.returnJson(False, '还未生成!', [])
field = 'time,ip,domain,server_name,method,uri,user_agent,rule_name,reason'
limit = str(page_size) + ' offset ' + str(page_size * (page - 1))
condition = ''
conn = conn.field(field)
conn = conn.where("1=1", ()).where("domain=?", (domain,))
clist = conn.limit(limit).order('time desc').inquiry()
count_key = "count(*) as num"
count = conn.field(count_key).limit('').order('').inquiry()
# print(count)
count = count[0][count_key]
files = os.listdir(path) data = {}
for f in files: _page = {}
if f == '.DS_Store': _page['count'] = count
continue _page['p'] = page
f = f.split('_') _page['row'] = page_size
if f[0] == args['siteName']: _page['tojs'] = tojs
fl = f[1].split('.') data['page'] = mw.getPage(_page)
data.append(fl[0]) data['data'] = clist
return mw.returnJson(True, 'ok!', data) return mw.returnJson(True, 'ok!', data)
@ -1142,6 +1201,8 @@ if __name__ == "__main__":
print(saveScanRule()) print(saveScanRule())
elif func == 'get_site_config': elif func == 'get_site_config':
print(getSiteConfig()) print(getSiteConfig())
elif func == 'get_default_site':
print(getDefaultSite())
elif func == 'get_site_config_byname': elif func == 'get_site_config_byname':
print(getSiteConfigByName()) print(getSiteConfigByName())
elif func == 'add_site_cdn_header': elif func == 'add_site_cdn_header':

@ -1611,7 +1611,6 @@ function siteWafConfig(siteName, type) {
function wafSite(){ function wafSite(){
owPost('get_site_config', {}, function(data){ owPost('get_site_config', {}, function(data){
var tmp = $.parseJSON(data.data); var tmp = $.parseJSON(data.data);
var rdata = $.parseJSON(tmp.data); var rdata = $.parseJSON(tmp.data);
@ -1621,24 +1620,12 @@ function wafSite(){
i += 1; i += 1;
tbody += '<tr>\ tbody += '<tr>\
<td><a onclick="siteWafConfig(\''+ k + '\')" class="sitename btlink" title="' + k + '">' + k + '</a></td>\ <td><a onclick="siteWafConfig(\''+ k + '\')" class="sitename btlink" title="' + k + '">' + k + '</a></td>\
<td>\ <td><input onclick="setSiteObjState(\''+ k + '\',\'get\')" type="checkbox" ' + (v.get ? 'checked' : '') + '><span class="' + back_css(v.total[1].value) + '" title="拦截GET渗透次数:' + v.total[1].value + '">' + v.total[1].value + '</span></td>\
<input onclick="setSiteObjState(\''+ k + '\',\'get\')" type="checkbox" ' + (v.get ? 'checked' : '') + '><span class="' + back_css(v.total[1].value) + '" title="拦截GET渗透次数:' + v.total[1].value + '">' + v.total[1].value + '</span>\ <td><input onclick="setSiteObjState(\''+ k + '\',\'post\')" type="checkbox" ' + (v.post ? 'checked' : '') + '><span class="' + back_css(v.total[0].value) + '" title="拦截POST渗透次数:' + v.total[0].value + '">' + v.total[0].value + '</span></td>\
</td>\ <td><input onclick="setSiteObjState(\''+ k + '\',\'user-agent\')" type="checkbox" ' + (v['user-agent'] ? 'checked' : '') + '><span class="' + back_css(v.total[3].value) + '" title="拦截恶意User-Agent次数:' + v.total[3].value + '">' + v.total[3].value + '</span></td>\
<td>\ <td><input onclick="setSiteObjState(\''+ k + '\',\'cookie\')" type="checkbox" ' + (v.cookie ? 'checked' : '') + '><span class="' + back_css(v.total[4].value) + '" title="拦截Cookie渗透次数:' + v.total[4].value + '">' + v.total[4].value + '</span></td>\
<input onclick="setSiteObjState(\''+ k + '\',\'post\')" type="checkbox" ' + (v.post ? 'checked' : '') + '><span class="' + back_css(v.total[0].value) + '" title="拦截POST渗透次数:' + v.total[0].value + '">' + v.total[0].value + '</span>\ <td><input onclick="setSiteObjState(\''+ k + '\',\'cdn\')" type="checkbox" ' + (v.cdn ? 'checked' : '') + '></td>\
</td>\ <td><input onclick="setSiteObjState(\''+ k + '\',\'cc\')" type="checkbox" ' + (v.cc.open ? 'checked' : '') + '><span class="' + back_css(v.total[2].value) + '" title="拦截CC攻击次数:' + v.total[2].value + '">' + v.total[2].value + '</span></td>\
<td>\
<input onclick="setSiteObjState(\''+ k + '\',\'user-agent\')" type="checkbox" ' + (v['user-agent'] ? 'checked' : '') + '><span class="' + back_css(v.total[3].value) + '" title="拦截恶意User-Agent次数:' + v.total[3].value + '">' + v.total[3].value + '</span>\
</td>\
<td>\
<input onclick="setSiteObjState(\''+ k + '\',\'cookie\')" type="checkbox" ' + (v.cookie ? 'checked' : '') + '><span class="' + back_css(v.total[4].value) + '" title="拦截Cookie渗透次数:' + v.total[4].value + '">' + v.total[4].value + '</span>\
</td>\
<td>\
<input onclick="setSiteObjState(\''+ k + '\',\'cdn\')" type="checkbox" ' + (v.cdn ? 'checked' : '') + '>\
</td>\
<td>\
<input onclick="setSiteObjState(\''+ k + '\',\'cc\')" type="checkbox" ' + (v.cc.open ? 'checked' : '') + '><span class="' + back_css(v.total[2].value) + '" title="拦截CC攻击次数:' + v.total[2].value + '">' + v.total[2].value + '</span>\
</td>\
<td>\ <td>\
<div class="ssh-item" style="margin-left:0">\ <div class="ssh-item" style="margin-left:0">\
<input class="btswitch btswitch-ios" id="closeget_'+ i + '" type="checkbox" ' + (v.open ? 'checked' : '') + '>\ <input class="btswitch btswitch-ios" id="closeget_'+ i + '" type="checkbox" ' + (v.open ? 'checked' : '') + '>\
@ -1646,7 +1633,7 @@ function wafSite(){
</div>\ </div>\
</td>\ </td>\
<td class="text-right"><a onclick="siteWafLog(\''+ k + '\')" class="btlink ' + (v.log_size > 0 ? 'dot' : '') + '">日志</a> | <a onclick="siteWafConfig(\'' + k + '\')" class="btlink"></a></td>\ <td class="text-right"><a onclick="siteWafLog(\''+ k + '\')" class="btlink ' + (v.log_size > 0 ? 'dot' : '') + '">日志</a> | <a onclick="siteWafConfig(\'' + k + '\')" class="btlink"></a></td>\
</tr>' </tr>';
}); });
var con = '<div class="lib-box">\ var con = '<div class="lib-box">\
@ -1680,24 +1667,181 @@ function wafSite(){
function wafHistory(){ function wafLogRequest(page){
var con = '<button class="btn btn-success btn-sm" onclick="UncoverAll()">解封所有</button>'; var args = {};
con += '<div class="divtable mt10">\ args['page'] = page;
<table class="table table-hover waftable" style="color:#fff;">\ args['page_size'] = 10;
<thead><tr><th width="18%">开始时间</th>\ args['site'] = $('select[name="site"]').val();
<th width="44%">IP</th>\
<th width="10%">站点</th>\
<th width="10%">封锁原因</th>\
<th width="10%">封锁时长</th>\
<th style="text-align: center;" width="10%">状态</th>\
</thead>\
</table>\
</div>';
$(".soft-man-con").html(con);
}
var query_date = 'today';
if ($('#time_choose').attr("data-name") != ''){
query_date = $('#time_choose').attr("data-name");
} else {
query_date = $('#search_time button.cur').attr("data-name");
}
args['query_date'] = query_date;
args['tojs'] = 'wafLogRequest';
owPost('get_logs_list', args, function(rdata){
var rdata = $.parseJSON(rdata.data);
var list = '';
var data = rdata.data.data;
if (data.length > 0){
for(i in data){
list += '<tr>';
list += '<td><span class="overflow_hide" style="width:112px;">' + getLocalTime(data[i]['time'])+'</span></td>';
list += '<td><span class="overflow_hide" style="width:50px;">' + data[i]['domain'] +'</span></td>';
list += '<td><span class="overflow_hide" style="width:60px;">' + data[i]['ip'] +'</span></td>';
list += '<td><span class="overflow_hide" style="width:50px;">' + data[i]['uri'] +'</span></td>';
list += '<td><span class="overflow_hide" style="width:50px;">' + data[i]['rule_name'] +'</span></td>';
list += '<td><span class="overflow_hide" style="width:200px;">' + data[i]['reason'] +'</span></td>';
list += '<td><a data-id="'+i+'" href="javascript:;" class="btlink details" title="详情">详情</a></td>';
list += '</tr>';
}
} else{
list += '<tr><td colspan="8" style="text-align:center;">封锁日志为空</td></tr>';
}
var table = '<div class="tablescroll">\
<table id="DataBody" class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0" style="border: 0 none;">\
<thead><tr>\
<th>时间</th>\
<th>域名</th>\
<th>IP</th>\
<th>URI</th>\
<th>规则名</th>\
<th>原因</th>\
<th style="text-align:right;">操作</th></tr></thead>\
<tbody>\
'+ list +'\
</tbody></table>\
</div>\
<div id="wsPage" class="dataTables_paginate paging_bootstrap page"></div>';
$('#ws_table').html(table);
$('#wsPage').html(rdata.data.page);
$(".tablescroll .details").click(function(){
var index = $(this).attr('data-id');
var res = data[index];
var ip = res.ip;
var time = getLocalTime(res.time);
layer.open({
type: 1,
title: "【"+time + "】详情",
area: '600px',
closeBtn: 1,
shadeClose: false,
content: '<div class="pd15 lib-box">\
<table class="table" style="border:#ddd 1px solid; margin-bottom:10px">\
<tbody><tr><th>时间</th><td>'+ time + '</td><th>IP</th><td><a class="btlink" href="javascript:add_log_ip_black(\'' + escapeHTML(ip) + '\')" title="">' + escapeHTML(ip) + '</a></td></tr><tr><th></th><td>' + escapeHTML(res.method) + '</td><th></th><td>' + escapeHTML(res.rule_name) + '</td></tr></tbody></table>\
<div><b style="margin-left:10px">URI地址</b></div>\
<div class="lib-con pull-left mt10"><div class="divpre">'+ escapeHTML(res.uri) + '</div></div>\
<div><b style="margin-left:10px">User-Agent</b></div>\
<div class="lib-con pull-left mt10"><div class="divpre">'+ escapeHTML(res.user_agent) + '</div></div>\
<div><b style="margin-left:10px">过滤规则</b></div>\
<div class="lib-con pull-left mt10"><div class="divpre">'+ escapeHTML(res.rule_name) + '</div></div>\
<div><b style="margin-left:10px">Reason</b></div>\
<div class="lib-con pull-left mt10"><div class="divpre">'+ escapeHTML(res.reason) + '</div></div>\
</div>'
})
});
});
}
function wafLogs(){ function wafLogs(){
var randstr = getRandomString(10);
var html = '<div>\
<div style="padding-bottom:10px;">\
<span>网站: </span>\
<select class="bt-input-text" name="site" style="margin-left:4px;width:100px;">\
<option value="unset">未设置</option>\
</select>\
<span style="margin-left:10px">时间: </span>\
<div class="input-group" style="margin-left:10px;width:350px;display: inline-table;vertical-align: top;">\
<div id="search_time" class="input-group-btn btn-group-sm">\
<button data-name="today" type="button" class="btn btn-default">今日</button>\
<button data-name="yesterday" type="button" class="btn btn-default">昨日</button>\
<button data-name="l7" type="button" class="btn btn-default">近7天</button>\
<button data-name="l30" type="button" class="btn btn-default">近30天</button>\
</div>\
<span class="last-span"><input data-name="" type="text" id="time_choose" lay-key="1000001_'+randstr+'" class="form-control btn-group-sm" autocomplete="off" placeholder="自定义时间" style="display: inline-block;font-size: 12px;padding: 0 10px;height:30px;width: 200px;"></span>\
</div>\
</div>\
<div class="divtable mtb10" id="ws_table"></div>\
</div>';
$(".soft-man-con").html(html);
// wafLogRequest(1);
//日期范围
laydate.render({
elem: '#time_choose',
value:'',
range:true,
done:function(value, startDate, endDate){
if(!value){
return false;
}
$('#search_time button').each(function(){
$(this).removeClass('cur');
});
var timeA = value.split('-');
var start = $.trim(timeA[0]+'-'+timeA[1]+'-'+timeA[2])
var end = $.trim(timeA[3]+'-'+timeA[4]+'-'+timeA[5])
query_txt = toUnixTime(start + " 00:00:00") + "-"+ toUnixTime(end + " 00:00:00")
$('#time_choose').attr("data-name",query_txt);
$('#time_choose').addClass("cur");
wsTableErrorLogRequest(1);
},
});
$('#search_time button:eq(0)').addClass('cur');
$('#search_time button').click(function(){
$('#search_time button').each(function(){
if ($(this).hasClass('cur')){
$(this).removeClass('cur');
}
});
$('#time_choose').attr("data-name",'');
$('#time_choose').removeClass("cur");
$(this).addClass('cur');
wafLogRequest(1);
});
owPost('get_default_site',{},function(rdata){
$('select[name="site"]').html('');
var rdata = $.parseJSON(rdata.data);
var rdata = rdata.data;
var default_site = rdata["default"];
var select = '';
for (var i = 0; i < rdata["list"].length; i++) {
if (default_site == rdata["list"][i]){
select += '<option value="'+rdata["list"][i]+'" selected>'+rdata["list"][i]+'</option>';
} else{
select += '<option value="'+rdata["list"][i]+'">'+rdata["list"][i]+'</option>';
}
}
$('select[name="site"]').html(select);
wafLogRequest(1);
$('select[name="site"]').change(function(){
wafLogRequest(1);
});
});
}
function wafOpLogs(){
var con = '<div class="divtable">\ var con = '<div class="divtable">\
<table class="table table-hover waftable" style="color:#fff;">\ <table class="table table-hover waftable" style="color:#fff;">\
<thead><tr><th width="18%">名称</th>\ <thead><tr><th width="18%">名称</th>\

@ -164,7 +164,7 @@ def test_scan():
''' '''
目录保存 目录保存
''' '''
url = TEST_URL + '/acunetix_wvs_security_test?t=1' url = TEST_URL + 'acunetix_wvs_security_test?t=1'
print("scan test start") print("scan test start")
url_val = httpGet(url, 10) url_val = httpGet(url, 10)
print(url_val) print(url_val)
@ -214,8 +214,8 @@ def test_start():
# test_UA() # test_UA()
# test_UA_for(1000) # test_UA_for(1000)
# test_POST() # test_POST()
# test_scan() test_scan()
test_CC() # test_CC()
# test_url_ext() # test_url_ext()
# test_cdn() # test_cdn()

@ -60,13 +60,13 @@ function _M.initDB(self)
db:exec([[PRAGMA journal_size_limit = 1073741824]]) db:exec([[PRAGMA journal_size_limit = 1073741824]])
self.db = db self.db = db
return self.db return db
end end
function _M.log(self, args, rule_name, reason) function _M.log(self, args, rule_name, reason)
local local_db = self:initDB() local local_db = self:initDB()
local stmt2 = local_db:prepare[[INSERT INTO logs(time, ip, domain, server_name, method, status_code, uri, rule_name, reason) local stmt2 = local_db:prepare[[INSERT INTO logs(time, ip, domain, server_name, method, status_code, uri, user_agent, rule_name, reason)
VALUES(:time, :ip, :domain, :server_name, :method, :status_code, :uri, :rule_name, :reason)]] VALUES(:time, :ip, :domain, :server_name, :method, :status_code, :uri, :user_agent, :rule_name, :reason)]]
local_db:exec([[BEGIN TRANSACTION]]) local_db:exec([[BEGIN TRANSACTION]])
@ -77,6 +77,7 @@ function _M.log(self, args, rule_name, reason)
server_name=args["server_name"], server_name=args["server_name"],
method=args["method"], method=args["method"],
status_code=args["status_code"], status_code=args["status_code"],
user_agent=args["user_agent"],
uri=args["request_uri"], uri=args["request_uri"],
rule_name=rule_name, rule_name=rule_name,
reason=reason reason=reason
@ -84,12 +85,12 @@ function _M.log(self, args, rule_name, reason)
local res, err = stmt2:step() local res, err = stmt2:step()
-- self:D("LOG[1]:"..tostring(res)..":"..tostring(err)) -- self:D("LOG[1]:"..tostring(res)..":"..tostring(err))
if tostring(res) == "5" then if tostring(res) == "5" then
self.D("waf the step database connection is busy, so it will be stored later.") self.D("waf the step database connection is busy, so it will be stored later.")
return false return false
end end
stmt2:reset() stmt2:reset()
local res, err = local_db:execute([[COMMIT]]) local res, err = local_db:execute([[COMMIT]])
-- self:D("LOG[2]:"..tostring(res)..":"..tostring(err)) -- self:D("LOG[2]:"..tostring(res)..":"..tostring(err))
if local_db and local_db:isopen() then if local_db and local_db:isopen() then

@ -45,6 +45,7 @@ local function initParams()
data['method'] = ngx.req.get_method() data['method'] = ngx.req.get_method()
data['request_uri'] = ngx.var.request_uri data['request_uri'] = ngx.var.request_uri
data['status_code'] = ngx.status data['status_code'] = ngx.status
data['user_agent'] = data['request_header']['user-agent']
data['cookie'] = ngx.var.http_cookie data['cookie'] = ngx.var.http_cookie
data['time'] = ngx.time() data['time'] = ngx.time()
return data return data

@ -2110,7 +2110,7 @@ laydate.render({
$(this).removeClass('cur'); $(this).removeClass('cur');
}); });
var timeA = value.split('-') var timeA = value.split('-');
var start = $.trim(timeA[0]+'-'+timeA[1]+'-'+timeA[2]) var start = $.trim(timeA[0]+'-'+timeA[1]+'-'+timeA[2])
var end = $.trim(timeA[3]+'-'+timeA[4]+'-'+timeA[5]) var end = $.trim(timeA[3]+'-'+timeA[4]+'-'+timeA[5])
query_txt = toUnixTime(start + " 00:00:00") + "-"+ toUnixTime(end + " 00:00:00") query_txt = toUnixTime(start + " 00:00:00") + "-"+ toUnixTime(end + " 00:00:00")

Loading…
Cancel
Save