diff --git a/README.md b/README.md index 204de0b..d562b22 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ ### ngx_lua_waf -ngx_lua_waf是一个基于lua-nginx-module的web应用防火墙 +ngx_lua_waf是一个基于lua-nginx-module的web应用防火墙, 支持验证码验证 ### OneinStack启用ngx_lua_waf ``` @@ -26,6 +26,7 @@ export LUAJIT_INC=/usr/local/include/luajit-2.1 sed -i "s@^nginx_modules_options=.*@nginx_modules_options='--with-ld-opt=-Wl,-rpath,/usr/local/lib --add-module=../lua-nginx-module --add-module=../ngx_devel_kit'@" options.conf ./install.sh --nginx_option 1 +### 全局nginx新增waf cat > /usr/local/nginx/conf/waf.conf << EOF lua_shared_dict limit 20m; lua_package_path "/usr/local/nginx/conf/waf/?.lua;;"; @@ -36,6 +37,23 @@ EOF #vi /usr/local/nginx/conf/nginx.conf #include vhost/*.conf;下一行新增,如下 include waf.conf; + +### 单网站新增waf(推荐) +cat > /usr/local/nginx/conf/waf.conf << EOF +lua_shared_dict limit 20m; +lua_package_path "/usr/local/nginx/conf/waf/?.lua;;"; +init_by_lua_file "/usr/local/nginx/conf/waf/init.lua"; +EOF + +#vi /usr/local/nginx/conf/vhost/www.example.com.conf +#location ~ [^/]\.php(/|$) {下一行新增,如下 +access_by_lua_file "/usr/local/nginx/conf/waf/access.lua"; +#注意:wordpress URL改成ngx.var.request_uri + 66 local ATTACK_URL = ngx.var.host .. ngx.var.uri + 67 -- local ATTACK_URL = ngx.var.host .. ngx.var.request_uri +#改成: + 66 -- local ATTACK_URL = ngx.var.host .. ngx.var.uri + 67 local ATTACK_URL = ngx.var.host .. ngx.var.request_uri ``` ### Copyright diff --git a/access.lua b/access.lua index 354b27d..5d27920 100644 --- a/access.lua +++ b/access.lua @@ -1,6 +1,6 @@ -require 'init' +require "init" -function waf_main() +local function waf_main() if black_ip_check() then elseif white_ip_check() then elseif white_url_check() then diff --git a/init.lua b/init.lua index d08c396..c8ed5f7 100644 --- a/init.lua +++ b/init.lua @@ -1,20 +1,20 @@ ---WAF Action -require 'config' -require 'lib' +-- WAF Action +require "config" +require "lib" ---args +-- args local rulematch = ngx.re.find local unescape = ngx.unescape_uri ---allow white ip +-- allow white ip function white_ip_check() if config_white_ip_check == "on" then - local IP_WHITE_RULE = get_rule('whiteip') + 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,"_","_") + -- log_record("White_IP",ngx.var_request_uri,"_","_") return true end end @@ -22,17 +22,18 @@ function white_ip_check() end end ---deny black ip +-- deny black ip function black_ip_check() if config_black_ip_check == "on" then - local IP_BLACK_RULE = get_rule('blackip') + 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) + ngx.header.content_type = "text/html" + ngx.say('Your IP blacklist, Please contact the administrator! ') return true end end @@ -41,10 +42,10 @@ function black_ip_check() end end ---allow white url +-- allow white url function white_url_check() if config_white_url_check == "on" then - local URL_WHITE_RULES = get_rule('whiteurl') + local URL_WHITE_RULES = get_rule("whiteurl") local REQ_URI = string.lower(ngx.var.request_uri) if URL_WHITE_RULES ~= nil then for _,rule in pairs(URL_WHITE_RULES) do @@ -56,23 +57,31 @@ function white_url_check() end end ---deny cc attack +-- 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 ARGS = ngx.var.args or "" + local ATTACK_URL = ngx.var.host .. ngx.var.uri + -- local ATTACK_URL = ngx.var.host .. ngx.var.request_uri + -- local ATTACK_URL = ngx.var.host .. ngx.var.uri .. '?' .. ARGS + local CC_TOKEN = get_client_ip() .. "." .. ngx.md5(string.lower(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 - --write('/data/wwwlogs/info.log',CC_TOKEN ..'\t'.. ATTACK_URL .. '\t'.. 'req: ' .. req .. "\n") + -- write("/data/wwwlogs/info.log",CC_TOKEN .."\t".. ATTACK_URL .. "\t".. "req: " .. req .."\n") if req > CCcount then - log_record('CC_Attack',ngx.var.request_uri,"-","-") + log_record("CC_Attack",ATTACK_URL,"-","-") if config_waf_enable == "on" then - ngx.exit(403) + local source = ngx.encode_base64(ngx.var.scheme.."://"..ngx.var.host..ngx.var.request_uri) + local dest = 'https://oneinstack.com/captcha.html' .. '?continue=' .. source + local CCcountcode,_ = math.modf(CCcount/2); + limit:set(CC_TOKEN,CCcountcode) + ngx.redirect(dest,302) end else limit:incr(CC_TOKEN,1) @@ -84,15 +93,15 @@ function cc_attack_check() return false end ---deny cookie +-- deny cookie function cookie_attack_check() if config_cookie_check == "on" then - local COOKIE_RULES = get_rule('cookie') + 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) + log_record("Deny_Cookie",ngx.var.request_uri,"-",rule) if config_waf_enable == "on" then waf_output() return true @@ -104,14 +113,14 @@ function cookie_attack_check() return false end ---deny url +-- deny url function url_attack_check() if config_url_check == "on" then - local URL_RULES = get_rule('blackurl') + local URL_RULES = get_rule("blackurl") local REQ_URI = string.lower(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) + log_record("Deny_URL",REQ_URI,"-",rule) if config_waf_enable == "on" then waf_output() return true @@ -122,20 +131,20 @@ function url_attack_check() return false end ---deny url args +-- 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, " ") + if type(val) == "table" then + local ARGS_DATA = table.concat(val, " ") else - ARGS_DATA = val + local 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) + log_record("Deny_URL_Args",ngx.var.request_uri,"-",rule) if config_waf_enable == "on" then waf_output() return true @@ -146,15 +155,15 @@ function url_args_attack_check() end return false end ---deny user agent +-- 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_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) + log_record("Deny_USER_AGENT",ngx.var.request_uri,"-",rule) if config_waf_enable == "on" then waf_output() return true @@ -166,10 +175,10 @@ function user_agent_attack_check() return false end ---deny post +-- deny post function post_attack_check() if config_post_check == "on" then - local POST_RULES = get_rule('post') + local POST_RULES = get_rule("post") for _,rule in pairs(ARGS_RULES) do local POST_ARGS = ngx.req.get_post_args() end diff --git a/lib.lua b/lib.lua index c61c393..7016bd8 100644 --- a/lib.lua +++ b/lib.lua @@ -1,9 +1,9 @@ ---waf core lib -require 'config' +-- waf core lib +require "config" ---Get the client IP +-- Get the client IP function get_client_ip() - CLIENT_IP = ngx.req.get_headers()["X_real_ip"] + local CLIENT_IP = ngx.req.get_headers()["X_real_ip"] if CLIENT_IP == nil then CLIENT_IP = ngx.req.get_headers()["X_Forwarded_For"] end @@ -16,24 +16,24 @@ function get_client_ip() return CLIENT_IP end ---Get the client user agent +-- Get the client user agent function get_user_agent() - USER_AGENT = ngx.var.http_user_agent + local USER_AGENT = ngx.var.http_user_agent if USER_AGENT == nil then USER_AGENT = "unknown" end return USER_AGENT end ---Get WAF rule +-- Get WAF rule function get_rule(rulefilename) - local io = require 'io' + 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 = {} + local RULE_TABLE = {} for line in RULE_FILE:lines() do table.insert(RULE_TABLE,line) end @@ -41,10 +41,10 @@ function get_rule(rulefilename) return(RULE_TABLE) end ---WAF log record for json,(use logstash codec => json) +-- 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 io = require "io" local LOG_PATH = config_log_dir local CLIENT_IP = get_client_ip() local USER_AGENT = get_user_agent() @@ -71,7 +71,7 @@ function log_record(method,url,data,ruletag) file:close() end ---test log +-- test log function write(logfile, msg) local fd,err = io.open(logfile,"a+") if fd == nil then @@ -83,7 +83,7 @@ function write(logfile, msg) fd:close() end ---WAF return +-- WAF return function waf_output() if config_waf_output == "redirect" then ngx.redirect(config_waf_redirect_url, 301)