commit
parent
b29cb04e6a
commit
3d9ff7687f
|
@ -23,6 +23,6 @@ sed -i "s@^nginx_modules_options=.*@nginx_modules_options='--add-module=../lua-n
|
|||
```
|
||||
|
||||
### Copyright
|
||||
完全copy以下项目:
|
||||
完全copy以下项目:<br />
|
||||
https://github.com/loveshell/ngx_lua_waf<br />
|
||||
https://github.com/unixhot/waf
|
||||
https://github.com/loveshell/ngx_lua_waf
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
require 'init'
|
||||
|
||||
function waf_main()
|
||||
if black_ip_check() then
|
||||
elseif white_ip_check() then
|
||||
elseif white_url_check() then
|
||||
elseif user_agent_attack_check() then
|
||||
elseif cc_attack_check() then
|
||||
elseif cookie_attack_check() then
|
||||
elseif url_attack_check() then
|
||||
elseif url_args_attack_check() then
|
||||
--elseif post_attack_check() then
|
||||
else
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
waf_main()
|
|
@ -0,0 +1,60 @@
|
|||
--WAF config file,enable = "on",disable = "off"
|
||||
|
||||
--waf status
|
||||
config_waf_enable = "on"
|
||||
--log dir
|
||||
config_log_dir = "/data/wwwlogs"
|
||||
--rule setting
|
||||
config_rule_dir = "/usr/local/nginx/conf/waf/wafconf"
|
||||
--enable/disable white url
|
||||
config_white_url_check = "on"
|
||||
--enable/disable white ip
|
||||
config_white_ip_check = "on"
|
||||
--enable/disable block ip
|
||||
config_black_ip_check = "on"
|
||||
--enable/disable url filtering
|
||||
config_url_check = "on"
|
||||
--enalbe/disable url args filtering
|
||||
config_url_args_check = "on"
|
||||
--enable/disable user agent filtering
|
||||
config_user_agent_check = "on"
|
||||
--enable/disable cookie deny filtering
|
||||
config_cookie_check = "on"
|
||||
--enable/disable cc filtering
|
||||
config_cc_check = "on"
|
||||
--cc rate the xxx of xxx seconds
|
||||
config_cc_rate = "20/60"
|
||||
--enable/disable post filtering
|
||||
config_post_check = "on"
|
||||
--config waf output redirect/html
|
||||
config_waf_output = "html"
|
||||
--if config_waf_output ,setting url
|
||||
config_waf_redirect_url = "/captcha"
|
||||
config_output_html=[[
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>网站防火墙</title>
|
||||
<style>
|
||||
p {
|
||||
line-height:20px;
|
||||
}
|
||||
ul{ list-style-type:none;}
|
||||
li{ list-style-type:none;}
|
||||
</style>
|
||||
</head>
|
||||
<body style=" padding:0; margin:0; font:14px/1.5 Microsoft Yahei, 宋体,sans-serif; color:#555;">
|
||||
<div style="margin: 0 auto; width:1000px; padding-top:70px; overflow:hidden;">
|
||||
<div style="width:600px; float:left;">
|
||||
<div style=" height:40px; line-height:40px; color:#fff; font-size:16px; overflow:hidden; background:#6bb3f6; padding-left:20px;">网站防火墙 </div>
|
||||
<div style="border:1px dashed #cdcece; border-top:none; font-size:14px; background:#fff; color:#555; line-height:24px; height:220px; padding:20px 20px 0 20px; overflow-y:auto;background:#f3f7f9;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600; color:#fc4f03;">您的请求带有不合法参数,已被网站管理员设置拦截!</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">可能原因:您提交的内容包含危险的攻击请求</p>
|
||||
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;">如何解决:</p>
|
||||
<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1)检查提交内容;</li>
|
||||
<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2)如网站托管,请联系空间提供商;</li>
|
||||
<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3)普通网站访客,请联系网站管理员;</li></ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body></html>
|
||||
]]
|
|
@ -0,0 +1,178 @@
|
|||
--WAF Action
|
||||
require 'config'
|
||||
require 'lib'
|
||||
|
||||
--args
|
||||
local rulematch = ngx.re.find
|
||||
local unescape = ngx.unescape_uri
|
||||
|
||||
--allow white ip
|
||||
function white_ip_check()
|
||||
if config_white_ip_check == "on" then
|
||||
local IP_WHITE_RULE = get_rule('whiteip')
|
||||
local WHITE_IP = get_client_ip()
|
||||
if IP_WHITE_RULE ~= nil then
|
||||
for _,rule in pairs(IP_WHITE_RULE) do
|
||||
if rule ~= "" and rulematch(WHITE_IP,rule,"jo") then
|
||||
log_record('White_IP',ngx.var_request_uri,"_","_")
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--deny black ip
|
||||
function black_ip_check()
|
||||
if config_black_ip_check == "on" then
|
||||
local IP_BLACK_RULE = get_rule('blackip')
|
||||
local BLACK_IP = get_client_ip()
|
||||
if IP_BLACK_RULE ~= nil then
|
||||
for _,rule in pairs(IP_BLACK_RULE) do
|
||||
if rule ~= "" and rulematch(BLACK_IP,rule,"jo") then
|
||||
log_record('BlackList_IP',ngx.var_request_uri,"_","_")
|
||||
if config_waf_enable == "on" then
|
||||
ngx.exit(403)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--allow white url
|
||||
function white_url_check()
|
||||
if config_white_url_check == "on" then
|
||||
local URL_WHITE_RULES = get_rule('whiteurl')
|
||||
local REQ_URI = ngx.var.request_uri
|
||||
if URL_WHITE_RULES ~= nil then
|
||||
for _,rule in pairs(URL_WHITE_RULES) do
|
||||
if rule ~= "" and rulematch(REQ_URI,rule,"jo") then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--deny cc attack
|
||||
function cc_attack_check()
|
||||
if config_cc_check == "on" then
|
||||
local USER_AGENT = get_user_agent()
|
||||
local ATTACK_URL = ngx.var.host .. ngx.var.request_uri
|
||||
local CC_TOKEN = get_client_ip() .. "." .. ngx.md5(ATTACK_URL .. USER_AGENT)
|
||||
local limit = ngx.shared.limit
|
||||
local CCcount=tonumber(string.match(config_cc_rate,'(.*)/'))
|
||||
local CCseconds=tonumber(string.match(config_cc_rate,'/(.*)'))
|
||||
local req,_ = limit:get(CC_TOKEN)
|
||||
if req then
|
||||
if req > CCcount then
|
||||
log_record('CC_Attack',ngx.var.request_uri,"-","-")
|
||||
if config_waf_enable == "on" then
|
||||
waf_output()
|
||||
ngx.exit(403)
|
||||
end
|
||||
else
|
||||
limit:incr(CC_TOKEN,1)
|
||||
end
|
||||
else
|
||||
limit:set(CC_TOKEN,1,CCseconds)
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
--deny cookie
|
||||
function cookie_attack_check()
|
||||
if config_cookie_check == "on" then
|
||||
local COOKIE_RULES = get_rule('cookie')
|
||||
local USER_COOKIE = ngx.var.http_cookie
|
||||
if USER_COOKIE ~= nil then
|
||||
for _,rule in pairs(COOKIE_RULES) do
|
||||
if rule ~="" and rulematch(USER_COOKIE,rule,"jo") then
|
||||
log_record('Deny_Cookie',ngx.var.request_uri,"-",rule)
|
||||
if config_waf_enable == "on" then
|
||||
waf_output()
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
--deny url
|
||||
function url_attack_check()
|
||||
if config_url_check == "on" then
|
||||
local URL_RULES = get_rule('blackurl')
|
||||
local REQ_URI = ngx.var.request_uri
|
||||
for _,rule in pairs(URL_RULES) do
|
||||
if rule ~="" and rulematch(REQ_URI,rule,"jo") then
|
||||
log_record('Deny_URL',REQ_URI,"-",rule)
|
||||
if config_waf_enable == "on" then
|
||||
waf_output()
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
--deny url args
|
||||
function url_args_attack_check()
|
||||
if config_url_args_check == "on" then
|
||||
local ARGS_RULES = get_rule('args')
|
||||
for _,rule in pairs(ARGS_RULES) do
|
||||
local REQ_ARGS = ngx.req.get_uri_args()
|
||||
for key, val in pairs(REQ_ARGS) do
|
||||
if type(val) == 'table' then
|
||||
ARGS_DATA = table.concat(val, " ")
|
||||
else
|
||||
ARGS_DATA = val
|
||||
end
|
||||
if ARGS_DATA and type(ARGS_DATA) ~= "boolean" and rule ~="" and rulematch(unescape(ARGS_DATA),rule,"jo") then
|
||||
log_record('Deny_URL_Args',ngx.var.request_uri,"-",rule)
|
||||
if config_waf_enable == "on" then
|
||||
waf_output()
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
--deny user agent
|
||||
function user_agent_attack_check()
|
||||
if config_user_agent_check == "on" then
|
||||
local USER_AGENT_RULES = get_rule('useragent')
|
||||
local USER_AGENT = ngx.var.http_user_agent
|
||||
if USER_AGENT ~= nil then
|
||||
for _,rule in pairs(USER_AGENT_RULES) do
|
||||
if rule ~="" and rulematch(USER_AGENT,rule,"jo") then
|
||||
log_record('Deny_USER_AGENT',ngx.var.request_uri,"-",rule)
|
||||
if config_waf_enable == "on" then
|
||||
waf_output()
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
--deny post
|
||||
function post_attack_check()
|
||||
if config_post_check == "on" then
|
||||
local POST_RULES = get_rule('post')
|
||||
for _,rule in pairs(ARGS_RULES) do
|
||||
local POST_ARGS = ngx.req.get_post_args()
|
||||
end
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
|
@ -0,0 +1,84 @@
|
|||
--waf core lib
|
||||
require 'config'
|
||||
|
||||
--Get the client IP
|
||||
function get_client_ip()
|
||||
CLIENT_IP = ngx.req.get_headers()["X_real_ip"]
|
||||
if CLIENT_IP == nil then
|
||||
CLIENT_IP = ngx.req.get_headers()["X_Forwarded_For"]
|
||||
end
|
||||
if CLIENT_IP == nil then
|
||||
CLIENT_IP = ngx.var.remote_addr
|
||||
end
|
||||
if CLIENT_IP == nil then
|
||||
CLIENT_IP = "unknown"
|
||||
end
|
||||
return CLIENT_IP
|
||||
end
|
||||
|
||||
--Get the client user agent
|
||||
function get_user_agent()
|
||||
USER_AGENT = ngx.var.http_user_agent
|
||||
if USER_AGENT == nil then
|
||||
USER_AGENT = "unknown"
|
||||
end
|
||||
return USER_AGENT
|
||||
end
|
||||
|
||||
--Get WAF rule
|
||||
function get_rule(rulefilename)
|
||||
local io = require 'io'
|
||||
local RULE_PATH = config_rule_dir
|
||||
local RULE_FILE = io.open(RULE_PATH..'/'..rulefilename,"r")
|
||||
if RULE_FILE == nil then
|
||||
return
|
||||
end
|
||||
RULE_TABLE = {}
|
||||
for line in RULE_FILE:lines() do
|
||||
table.insert(RULE_TABLE,line)
|
||||
end
|
||||
RULE_FILE:close()
|
||||
return(RULE_TABLE)
|
||||
end
|
||||
|
||||
--WAF log record for json,(use logstash codec => json)
|
||||
function log_record(method,url,data,ruletag)
|
||||
local cjson = require("cjson")
|
||||
local io = require 'io'
|
||||
local LOG_PATH = config_log_dir
|
||||
local CLIENT_IP = get_client_ip()
|
||||
local USER_AGENT = get_user_agent()
|
||||
local SERVER_NAME = ngx.var.host
|
||||
local LOCAL_TIME = ngx.localtime()
|
||||
local log_json_obj = {
|
||||
client_ip = CLIENT_IP,
|
||||
local_time = LOCAL_TIME,
|
||||
server_name = SERVER_NAME,
|
||||
req_url = url,
|
||||
attack_method = method,
|
||||
req_data = data,
|
||||
rule_tag = ruletag,
|
||||
user_agent = USER_AGENT,
|
||||
}
|
||||
local LOG_LINE = cjson.encode(log_json_obj)
|
||||
local LOG_NAME = LOG_PATH..'/'..ngx.today().."_sec.log"
|
||||
local file = io.open(LOG_NAME,"a")
|
||||
if file == nil then
|
||||
return
|
||||
end
|
||||
file:write(LOG_LINE.."\n")
|
||||
file:flush()
|
||||
file:close()
|
||||
end
|
||||
|
||||
--WAF return
|
||||
function waf_output()
|
||||
if config_waf_output == "redirect" then
|
||||
ngx.redirect(config_waf_redirect_url, 301)
|
||||
else
|
||||
ngx.header.content_type = "text/html"
|
||||
ngx.status = ngx.HTTP_FORBIDDEN
|
||||
ngx.say(config_output_html)
|
||||
ngx.exit(ngx.status)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,22 @@
|
|||
\.\./
|
||||
\:\$
|
||||
\$\{
|
||||
select.+(from|limit)
|
||||
(?:(union(.*?)select))
|
||||
having|rongjitest
|
||||
sleep\((\s*)(\d*)(\s*)\)
|
||||
benchmark\((.*)\,(.*)\)
|
||||
base64_decode\(
|
||||
(?:from\W+information_schema\W)
|
||||
(?:(?:current_)user|database|schema|connection_id)\s*\(
|
||||
(?:etc\/\W*passwd)
|
||||
into(\s+)+(?:dump|out)file\s*
|
||||
group\s+by.+\(
|
||||
xwork.MethodAccessor
|
||||
(?: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)\(
|
||||
xwork\.MethodAccessor
|
||||
(gopher|doc|php|glob|file|phar|zlib|ftp|ldap|dict|ogg|data)\:\/
|
||||
java\.lang
|
||||
\$_(GET|post|cookie|files|session|env|phplib|GLOBALS|SERVER)\[
|
||||
\<(iframe|script|body|img|layer|div|meta|style|base|object|input)
|
||||
(onmouseover|onerror|onload)\=
|
|
@ -0,0 +1,6 @@
|
|||
\.(htaccess|bash_history)
|
||||
\.(bak|inc|old|mdb|sql|backup|java|class|tgz|gz|tar|zip)$
|
||||
(phpmyadmin|jmx-console|admin-console|jmxinvokerservlet)
|
||||
java\.lang
|
||||
\.svn\/
|
||||
/(attachments|upimg|images|css|uploadfiles|html|uploads|templets|static|template|data|inc|forumdata|upload|includes|cache|avatar)/(\\w+).(php|jsp)
|
|
@ -0,0 +1,20 @@
|
|||
\.\./
|
||||
\:\$
|
||||
\$\{
|
||||
select.+(from|limit)
|
||||
(?:(union(.*?)select))
|
||||
having|rongjitest
|
||||
sleep\((\s*)(\d*)(\s*)\)
|
||||
benchmark\((.*)\,(.*)\)
|
||||
base64_decode\(
|
||||
(?:from\W+information_schema\W)
|
||||
(?:(?:current_)user|database|schema|connection_id)\s*\(
|
||||
(?:etc\/\W*passwd)
|
||||
into(\s+)+(?:dump|out)file\s*
|
||||
group\s+by.+\(
|
||||
xwork.MethodAccessor
|
||||
(?: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)\(
|
||||
xwork\.MethodAccessor
|
||||
(gopher|doc|php|glob|file|phar|zlib|ftp|ldap|dict|ogg|data)\:\/
|
||||
java\.lang
|
||||
\$_(GET|post|cookie|files|session|env|phplib|GLOBALS|SERVER)\[
|
|
@ -0,0 +1,20 @@
|
|||
\.\./
|
||||
select.+(from|limit)
|
||||
(?:(union(.*?)select))
|
||||
having|rongjitest
|
||||
sleep\((\s*)(\d*)(\s*)\)
|
||||
benchmark\((.*)\,(.*)\)
|
||||
base64_decode\(
|
||||
(?:from\W+information_schema\W)
|
||||
(?:(?:current_)user|database|schema|connection_id)\s*\(
|
||||
(?:etc\/\W*passwd)
|
||||
into(\s+)+(?:dump|out)file\s*
|
||||
group\s+by.+\(
|
||||
xwork.MethodAccessor
|
||||
(?: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)\(
|
||||
xwork\.MethodAccessor
|
||||
(gopher|doc|php|glob|file|phar|zlib|ftp|ldap|dict|ogg|data)\:\/
|
||||
java\.lang
|
||||
\$_(GET|post|cookie|files|session|env|phplib|GLOBALS|SERVER)\[
|
||||
\<(iframe|script|body|img|layer|div|meta|style|base|object|input)
|
||||
(onmouseover|onerror|onload)\=
|
|
@ -0,0 +1 @@
|
|||
(HTTrack|harvest|audit|dirbuster|pangolin|nmap|sqln|-scan|hydra|Parser|libwww|BBBike|sqlmap|w3af|owasp|Nikto|fimap|havij|PycURL|zmeu|BabyKrokodil|netsparker|httperf|bench)
|
|
@ -0,0 +1 @@
|
|||
127.0.0.1
|
|
@ -0,0 +1,2 @@
|
|||
\.(js|css)$
|
||||
\.(gif|jpg|jpeg|png|bmp|swf|flv|mp4|ico)$
|
Loading…
Reference in New Issue