diff --git a/README.md b/README.md
index 69dce8d..77408c5 100644
--- a/README.md
+++ b/README.md
@@ -23,6 +23,6 @@ sed -i "s@^nginx_modules_options=.*@nginx_modules_options='--add-module=../lua-n
```
### Copyright
-完全copy以下项目:
+完全copy以下项目:
+https://github.com/loveshell/ngx_lua_waf
https://github.com/unixhot/waf
-https://github.com/loveshell/ngx_lua_waf
diff --git a/access.lua b/access.lua
new file mode 100644
index 0000000..354b27d
--- /dev/null
+++ b/access.lua
@@ -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()
diff --git a/config.lua b/config.lua
new file mode 100644
index 0000000..b91ff98
--- /dev/null
+++ b/config.lua
@@ -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=[[
+
+
+网站防火墙
+
+
+
+
+
+
网站防火墙
+
+
您的请求带有不合法参数,已被网站管理员设置拦截!
+
可能原因:您提交的内容包含危险的攻击请求
+
如何解决:
+
- 1)检查提交内容;
+ - 2)如网站托管,请联系空间提供商;
+ - 3)普通网站访客,请联系网站管理员;
+
+
+
+
+]]
diff --git a/init.lua b/init.lua
new file mode 100644
index 0000000..327a393
--- /dev/null
+++ b/init.lua
@@ -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
diff --git a/lib.lua b/lib.lua
new file mode 100644
index 0000000..b30e3db
--- /dev/null
+++ b/lib.lua
@@ -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
diff --git a/wafconf/args b/wafconf/args
new file mode 100644
index 0000000..d5bf8e8
--- /dev/null
+++ b/wafconf/args
@@ -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)\=
diff --git a/wafconf/blackip b/wafconf/blackip
new file mode 100644
index 0000000..e69de29
diff --git a/wafconf/blackurl b/wafconf/blackurl
new file mode 100644
index 0000000..0eccfec
--- /dev/null
+++ b/wafconf/blackurl
@@ -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)
diff --git a/wafconf/cookie b/wafconf/cookie
new file mode 100644
index 0000000..30554ca
--- /dev/null
+++ b/wafconf/cookie
@@ -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)\[
diff --git a/wafconf/post b/wafconf/post
new file mode 100644
index 0000000..3b2365b
--- /dev/null
+++ b/wafconf/post
@@ -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)\=
diff --git a/wafconf/useragent b/wafconf/useragent
new file mode 100644
index 0000000..b3edddf
--- /dev/null
+++ b/wafconf/useragent
@@ -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)
diff --git a/wafconf/whiteip b/wafconf/whiteip
new file mode 100644
index 0000000..7b9ad53
--- /dev/null
+++ b/wafconf/whiteip
@@ -0,0 +1 @@
+127.0.0.1
diff --git a/wafconf/whiteurl b/wafconf/whiteurl
new file mode 100644
index 0000000..00b54a5
--- /dev/null
+++ b/wafconf/whiteurl
@@ -0,0 +1,2 @@
+\.(js|css)$
+\.(gif|jpg|jpeg|png|bmp|swf|flv|mp4|ico)$