diff --git a/plugins/op_waf/index.py b/plugins/op_waf/index.py index ccc182050..9dafdf829 100755 --- a/plugins/op_waf/index.py +++ b/plugins/op_waf/index.py @@ -118,6 +118,7 @@ def initSiteInfo(): cjson = public.getJson(site_contents_new) public.writeFile(path_site, cjson) + def initTotalInfo(): data = [] path_domains = getJsonPath('domains') @@ -135,7 +136,7 @@ def initTotalInfo(): total_contents_new = {} for x in range(len(domain_contents)): name = domain_contents[x]['name'] - if 'sites' in total_contents and name in total_contents['sites']: + if 'sites' in total_contents and name in total_contents['sites']: pass else: tmp = {} @@ -339,18 +340,18 @@ def getSiteConfig(): total_content = json.loads(total_content) # print total_content - + for x in content: tmp = [] tmp_v = {} if 'sites' in total_content and x in total_content['sites']: - tmp_v = total_content['sites'][x]; - - key_list = ['get','post','user-agent','cookie','cdn','cc'] + tmp_v = total_content['sites'][x] + + key_list = ['get', 'post', 'user-agent', 'cookie', 'cdn', 'cc'] for kx in range(len(key_list)): ktmp = {} - if kx in tmp_v : + if kx in tmp_v: ktmp['value'] = tmp_v[key_list[kx]] else: ktmp['value'] = '' @@ -360,10 +361,54 @@ def getSiteConfig(): # print tmp content[x]['total'] = tmp - content = public.getJson(content) return public.returnJson(True, 'ok!', content) + +def getLogsList(): + args = getArgs() + data = checkArgs(args, ['siteName']) + if not data[0]: + return data[1] + + data = [] + path = public.getLogsDir() + '/waf' + files = os.listdir(path) + for f in files: + if f == '.DS_Store': + continue + f = f.split('_') + if f[0] == args['siteName']: + fl = f[1].split('.') + data.append(fl[0]) + + return public.returnJson(True, 'ok!', data) + + +def getSafeLogs(): + args = getArgs() + data = checkArgs(args, ['siteName', 'toDate', 'p']) + if not data[0]: + return data[1] + + path = public.getLogsDir() + '/waf' + file = path + '/' + args['siteName'] + '_' + args['toDate'] + '.log' + if not os.path.exists(file): + return public.returnJson(False, "文件不存在!") + + retData = [] + file = open(file) + while 1: + lines = file.readlines(100000) + if not lines: + break + for line in lines: + + retData.append(json.loads(line)) + + return public.returnJson(True, '设置成功!', retData) + + def setObjOpen(): args = getArgs() data = checkArgs(args, ['obj']) @@ -427,6 +472,10 @@ if __name__ == "__main__": print saveScanRule() elif func == 'get_site_config': print getSiteConfig() + elif func == 'get_logs_list': + print getLogsList() + elif func == 'get_safe_logs': + print getSafeLogs() elif func == 'waf_srceen': print getWafSrceen() elif func == 'waf_conf': diff --git a/plugins/op_waf/js/op_waf.js b/plugins/op_waf/js/op_waf.js index eae323f1e..d9e96681c 100755 --- a/plugins/op_waf/js/op_waf.js +++ b/plugins/op_waf/js/op_waf.js @@ -865,6 +865,357 @@ function back_css(v) { } } +//查看网站日志 +function siteWafLog(siteName) { + var loadT = layer.msg('正在处理,请稍候..', { icon: 16, time: 0 }); + owPost('get_logs_list', { siteName: siteName } , function (data) { + var tmp = $.parseJSON(data.data); + var rdata = tmp.data; + var selectLogDay = ""; + var day = rdata[0]; + for (var i = 0; i < rdata.length; i++) { + selectLogDay += ''; + } + if (rdata == "") { + layer.msg("暂无日志记录", { icon: 6, shade: 0.3, time: 1000 }); + return + } + layer.open({ + type: 1, + title: "日志【" + siteName + "】", + area: ['880px', '500px'], + closeBtn: 2, + shadeClose: false, + content: '
\ +
\ +
\ +
\ +
\ + \ + \ + \ +
时间用户IP类型URI地址User-Agent状态过滤器过滤规则操作
\ +
\ +
\ +
\ +
\ +
' + }); + siteLogCon(siteName, day, 1); + tableFixed("site_waf_log"); + }); +} + + +//日志内容 +function siteLogCon(siteName, day, page) { + if (!page) page = 1; + var last = page - 1; + var next = page + 1; + var pagehtml = ''; + $("#site_waf_log").scrollTop(0); + + owPost('get_safe_logs', { siteName: siteName, toDate: day, p: page }, function(data){ + var tmp = $.parseJSON(data.data); + if (!tmp.status){ + layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 }); + return; + } + var rdata = tmp.data; + var con = ''; + for (var i = 0; i < rdata.length; i++) { + con += '\ + '+ escapeHTML(rdata[i][0]) + '\ + ' + escapeHTML(rdata[i][1]) + '\ + '+ escapeHTML(rdata[i][2]) + '\ + '+ escapeHTML(rdata[i][3]) + '\ + '+ escapeHTML(rdata[i][4]) + '已拦截\ + '+ escapeHTML(rdata[i][5]) + '\ + '+ escapeHTML(rdata[i][6]) + '\ + 误报 | 详细\ + ' + } + + $("#LogDayCon").html(con); + pagehtml = '首页上一页下一页第 ' + page + ' 页'; + $("#size_log_page").html(pagehtml); + if (rdata.length < 1) $(".nextPage").hide(); + if (last < 1) $(".prevPage").hide(); + + // 发送误报请求 + $(".submit_msg").click(function () { + var _this = $(this); + var res = rdata[$(this).attr('data-index')]; + layer.confirm('是否确定提交误报反馈?', { title: '误报反馈',closeBtn:2,icon:3}, function () { + var url_address = res[3]; + var rule_arry = res[6].split(" >> "); + var pdata = { url_rule: url_address }; + var loadT = layer.msg('正在添加URL白名单..', { icon: 16, time: 0 }); + $.post('/plugin?action=a&name=btwaf&s=add_url_white', pdata, function (rdata) { + layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 }); + layer.close(loadT); + if (rule_arry[1] != undefined){ $.get('https://www.bt.cn/Api/add_waf_logs?data=' + rule_arry[1],function(rdata){},'jsonp')} + }); + }); + }) + + // 详情 + $(".btwaf_details").click(function () { + var res = rdata[$(this).attr('data-index')]; + var time = res[0]; //时间 + var ip_address = res[1]; //IP地址 + var req_type = res[2]; // 请求类型 + var url_address = res[3]; // 请求类型 + var user_agent = res[4]; // 请求类型 + var filters = res[5]; //过滤器 + var filter_rule = ''; //过滤规则 + var rule_arry = res[6].split(" >> "); + var incoming_value = '',risk_value = ''; //传入值,风险值 + if(rule_arry.length == 0) filter_rule = rule_arry[0] + incoming_value = rule_arry[1] == undefined?'空':rule_arry[1]; + risk_value = incoming_value.match(new RegExp(rule_arry[0].replace(/\//g,'\\/'),'i')); + risk_value = risk_value?risk_value[0]:'空'; + + layer.open({ + type: 1, + title: time + "详情", + area: '600px', + closeBtn: 2, + shadeClose: false, + content: '
\ + \ +
时间'+ escapeHTML(time) + '用户IP' + escapeHTML(ip_address) + '
类型' + escapeHTML(req_type) + '过滤器' + escapeHTML(filters) + '
\ +
URI地址
\ +
'+ escapeHTML(url_address) + '
\ +
User-Agent
\ +
'+ escapeHTML(user_agent) + '
\ +
过滤规则
\ +
'+ escapeHTML(rule_arry[0]) + '
\ +
传入值
\ +
'+ escapeHTML(incoming_value) + '
\ +
风险值
\ +
'+ escapeHTML(risk_value) + '
\ +
' + }) + }) + $("#LogDayCon td").click(function () { + $(this).parents("tr").addClass("active").siblings().removeClass("active"); + }); + + }); +} + +function html_encode(value) { + return $('
').html(value).text(); +} + +function html_decode(value) { + return $('
').text(value).html(); +} + + +//网站设置 +function siteWafConfig(siteName, type) { + if (type == undefined) { + create_2 = layer.open({ + type: 1, + title: "网站配置【" + siteName + "】", + area: ['700px', '500px'], + closeBtn: 2, + shadeClose: false, + content: '
' + }); + } + var loadT = layer.msg('正在获取网站配置..', { icon: 16, time: 0 }); + $.post('/plugin?action=a&name=btwaf&s=get_site_config_byname', { siteName: siteName }, function (rdata) { + nginx_config = rdata; + layer.close(loadT); + var con = '
\ +
\ + 网站防火墙开关\ +
\ + \ + \ +
\ +
\ +
\ +
\ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ +
名称描述状态操作
CC防御'+ rdata.cc.cycle + ' 秒内,请求同一URI累计超过 ' + rdata.cc.limit + ' 次,封锁IP ' + rdata.cc.endtime + '\ +
\ + \ + \ +
\ +
设置
恶意容忍设置'+ rdata.retry_cycle + ' 秒内,累计超过 ' + rdata.retry + ' 次恶意请求,封锁IP ' + rdata.retry_time + '  --设置
GET-URI过滤'+ rdata.top.get.ps + '\ +
\ + \ + \ +
\ +
规则
GET-参数过滤'+ rdata.top.get.ps + '\ +
\ + \ + \ +
\ +
规则
POST过滤'+ rdata.top.post.ps + '\ +
\ + \ + \ +
\ +
规则
User-Agent过滤'+ rdata.top['user-agent'].ps + '\ +
\ + \ + \ +
\ +
规则
Cookie过滤'+ rdata.top.cookie.ps + '\ +
\ + \ + \ +
\ +
规则
禁止国外访问'+ rdata.top.drop_abroad.ps + '\ +
\ + \ + \ +
\ +
设置
常见扫描器'+ rdata.top.scan.ps + '\ +
\ + \ + \ +
\ +
设置
使用CDN该站点使用了CDN,启用后方可正确获取客户IP\ +
\ + \ + \ +
\ +
设置
禁止执行PHP的URL禁止在指定URL运行PHP脚本  --设置
禁止访问的URL禁止访问指定的URL  --设置
禁止扩展名禁止访问指定扩展名  --设置
禁止上传的文件类型禁止上传指定的文件类型  --设置
受保护的URL通过自定义参数加密URL地址,参数错误将被拦截  --设置
URL专用过滤为特定URL地址设置过滤规则  --设置
敏感文字替换替换设置的敏感文字  --设置
CMS专用过滤为特定CMS提供的过滤规则  --设置
\ +
\ +
\ + \ +
'; + $("#s_w_c").html(con); + }); +} + + + function wafSite(){ owPost('get_site_config', {}, function(data){ @@ -900,10 +1251,10 @@ function wafSite(){ \
\ \ - \ + \
\ \ - 日志 | 设置\ + 日志 | 设置\ ' }); diff --git a/plugins/op_waf/waf/config.json b/plugins/op_waf/waf/config.json index 18e38c53f..8ef61762c 100755 --- a/plugins/op_waf/waf/config.json +++ b/plugins/op_waf/waf/config.json @@ -1 +1 @@ -{"reqfile_path": "/Users/midoks/Desktop/fwww/server/openresty/nginx/conf/waf/html", "retry": {"retry_time": "180", "is_open_global": "0", "retry": "6", "retry_cycle": "60"}, "log": true, "retry_cycle": 60, "scan": {"status": 444, "ps": "\u8fc7\u6ee4\u5e38\u89c1\u626b\u63cf\u6d4b\u8bd5\u5de5\u5177\u7684\u6e17\u900f\u6d4b\u8bd5", "open": true, "reqfile": ""}, "cc": {"status": 444, "ps": "\u8fc7\u8651CC\u653b\u51fb", "limit": 120, "endtime": 300, "open": true, "reqfile": "", "cycle": 60}, "body_character_string": [], "start_time": 1556095983.425878, "get": {"status": 403, "ps": "\u8fc7\u6ee4uri\u3001uri\u53c2\u6570\u4e2d\u5e38\u89c1sql\u6ce8\u5165\u3001xss\u7b49\u653b\u51fb", "open": true, "reqfile": "get.html"}, "body_regular": [], "log_save": 30, "user-agent": {"status": 403, "ps": "\u901a\u5e38\u7528\u4e8e\u8fc7\u6ee4\u6d4f\u89c8\u5668\u3001\u8718\u86db\u53ca\u4e00\u4e9b\u81ea\u52a8\u626b\u63cf\u5668", "open": true, "reqfile": "user_agent.html"}, "retry_time": 180, "other": {"status": 403, "ps": "\u5176\u5b83\u975e\u901a\u7528\u8fc7\u6ee4", "reqfile": "other.html"}, "cookie": {"status": 403, "ps": "\u8fc7\u6ee4\u5229\u7528Cookie\u53d1\u8d77\u7684\u6e17\u900f\u653b\u51fb", "open": true, "reqfile": "cookie.html"}, "logs_path": "/www/wwwlogs/btwaf", "post": {"status": 403, "ps": "\u8fc7\u6ee4POST\u53c2\u6570\u4e2d\u5e38\u89c1sql\u6ce8\u5165\u3001xss\u7b49\u653b\u51fb", "open": true, "reqfile": "post.html"}, "open": true} \ No newline at end of file +{"reqfile_path": "/Users/midoks/Desktop/fwww/server/openresty/nginx/conf/waf/html", "retry": {"retry_time": "180", "is_open_global": "0", "retry": "6", "retry_cycle": "60"}, "log": true, "retry_cycle": 60, "scan": {"status": 444, "ps": "\u8fc7\u6ee4\u5e38\u89c1\u626b\u63cf\u6d4b\u8bd5\u5de5\u5177\u7684\u6e17\u900f\u6d4b\u8bd5", "open": true, "reqfile": ""}, "cc": {"status": 444, "ps": "\u8fc7\u8651CC\u653b\u51fb", "limit": 120, "endtime": 300, "open": true, "reqfile": "", "cycle": 60}, "body_character_string": [], "start_time": 1556095983.425878, "get": {"status": 403, "ps": "\u8fc7\u6ee4uri\u3001uri\u53c2\u6570\u4e2d\u5e38\u89c1sql\u6ce8\u5165\u3001xss\u7b49\u653b\u51fb", "open": true, "reqfile": "get.html"}, "body_regular": [], "log_save": 30, "user-agent": {"status": 403, "ps": "\u901a\u5e38\u7528\u4e8e\u8fc7\u6ee4\u6d4f\u89c8\u5668\u3001\u8718\u86db\u53ca\u4e00\u4e9b\u81ea\u52a8\u626b\u63cf\u5668", "open": true, "reqfile": "user_agent.html"}, "logs_path": "/www/wwwlogs/btwaf", "other": {"status": 403, "ps": "\u5176\u5b83\u975e\u901a\u7528\u8fc7\u6ee4", "reqfile": "other.html"}, "cookie": {"status": 403, "ps": "\u8fc7\u6ee4\u5229\u7528Cookie\u53d1\u8d77\u7684\u6e17\u900f\u653b\u51fb", "open": true, "reqfile": "cookie.html"}, "retry_time": 180, "post": {"status": 403, "ps": "\u8fc7\u6ee4POST\u53c2\u6570\u4e2d\u5e38\u89c1sql\u6ce8\u5165\u3001xss\u7b49\u653b\u51fb", "open": true, "reqfile": "post.html"}, "open": true} \ No newline at end of file diff --git a/route/static/app/public.js b/route/static/app/public.js index 8348d3c4e..ccf2ae8c6 100755 --- a/route/static/app/public.js +++ b/route/static/app/public.js @@ -22,6 +22,14 @@ function tableFixed(name) { tableName.addEventListener('scroll', scrollHandle); } +function escapeHTML(a){ + a = "" + a; + return a.replace(/&/g, "&").replace(//g, ">").replace(/"/g, '"'). + replace(/'/g,"‘").replace(/\(/g,"(").replace(/\</g,"<"). + replace(/\>/g,">").replace(/`/g,"`").replace(/=/g,"="); +} + function scrollHandle(e) { var scrollTop = this.scrollTop; //this.querySelector('thead').style.transform = 'translateY(' + scrollTop + 'px)';