Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

打个包,增加cc拦截效果,增加日志功能,增加白名单功能。 #136

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,34 @@
水平太烂,只能在原基础上改改。

1.原cc功能有点弱,改进后可以提高对攻击和普通访问的限制

默认同ip触发规则攻击超过10次/5秒,限制该ip访问nginx服务器1800秒。

同1 ip访问同1地址30次/60秒,限制访问该地址30秒。

2.日志主要是用于syslog服务器能力。

1.--保存日志到syslog,可以用nginx设置的日志服务器保存日志。

logtoserver = "on"

2.--通过加载socket.lua同时使用其他日志服务器,默认关闭。(这个有点粗糙,有需要的自己改)

loghack="off"

3.修改whiteurl,可以针对域名设置白名单。

--whiteurl start

site:^www.baidu.com/whiteurl/

--end


------------------分割线-------------------------------------------------

---------------lovshell记录----------------------------------------------

##ngx_lua_waf

ngx_lua_waf是我刚入职趣游时候开发的一个基于ngx_lua的web应用防火墙。
Expand Down Expand Up @@ -136,3 +167,51 @@ nginx安装路径假设为:/usr/local/nginx/conf/
</table>

感谢ngx_lua模块的开发者[@agentzh](https://github.com/agentzh/),春哥是我所接触过开源精神最好的人


syntax: captures, err = ngx.re.match(subject, regex, options?, ctx?, res_table?)
syntax: from, to, err = ngx.re.find(subject, regex, options?, ctx?, nth?)

Specify options to control how the match operation will be performed. The following option characters are supported:

a anchored mode (only match from the beginning)

d enable the DFA mode (or the longest token match semantics).
this requires PCRE 6.0+ or else a Lua exception will be thrown.
first introduced in ngx_lua v0.3.1rc30.

D enable duplicate named pattern support. This allows named
subpattern names to be repeated, returning the captures in
an array-like Lua table. for example,
local m = ngx.re.match("hello, world",
"(?<named>\w+), (?<named>\w+)",
"D")
-- m["named"] == {"hello", "world"}
this option was first introduced in the v0.7.14 release.
this option requires at least PCRE 8.12.

i case insensitive mode (similar to Perl's /i modifier)

j enable PCRE JIT compilation, this requires PCRE 8.21+ which
must be built with the --enable-jit option. for optimum performance,
this option should always be used together with the 'o' option.
first introduced in ngx_lua v0.3.1rc30.

J enable the PCRE Javascript compatible mode. this option was
first introduced in the v0.7.14 release. this option requires
at least PCRE 8.12.

m multi-line mode (similar to Perl's /m modifier)

o compile-once mode (similar to Perl's /o modifier),
to enable the worker-process-level compiled-regex cache

s single-line mode (similar to Perl's /s modifier)

u UTF-8 mode. this requires PCRE to be built with
the --enable-utf8 option or else a Lua exception will be thrown.

U similar to "u" but disables PCRE's UTF-8 validity check on
the subject string. first introduced in ngx_lua v0.8.1.

x extended mode (similar to Perl's /x modifier)
24 changes: 18 additions & 6 deletions config.lua
Original file line number Diff line number Diff line change
@@ -1,23 +1,35 @@
RulePath = "/usr/local/nginx/conf/waf/wafconf/"
RulePath = "/etc/nginx/waf/wafconf/"
attacklog = "on"
logdir = "/usr/local/nginx/logs/hack/"
--保存日志到文件
logtofile = "off"
logdir = "/var/log/nginx/"
--保存日志到syslog,采用nginx设置
logtoserver = "on"
--通过syslog日志方式提交hack_ip记录到日志服务器
loghack="off"
------------
UrlDeny="on"
Redirect="on"
CookieMatch="on"
postMatch="on"
whiteModule="on"
black_fileExt={"php","jsp"}
ipWhitelist={"127.0.0.1"}
ipWhitelist={"127.0.0.1","192.168.2.1"}
ipBlocklist={"1.0.0.1"}
CCDeny="off"
CCrate="100/60"
--违规ip登记,是否限制访问。
--hackrate超过10次/5秒,限制访问1800秒。
hackipdeny="on"
hackrate="10/60/1800"
--cc攻击防范
CCDeny="on"
CCrate="30/60/30"
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;
line-height:20px;
}
ul{ list-style-type:none;}
li{ list-style-type:none;}
Expand Down
143 changes: 126 additions & 17 deletions init.lua
Original file line number Diff line number Diff line change
@@ -1,19 +1,52 @@
require 'config'
local match = string.match
local ngxmatch=ngx.re.match
--ngx_lua如果是0.9.2以上版本,建议正则过滤函数改为ngx.re.find,匹配效率会提高三倍左右。
--因nginx和lua一起的关系,正则表达式使用\d\w\s会出问题,
--local ngxmatch=ngx.re.match
local ngxmatch=ngx.re.find
local unescape=ngx.unescape_uri
local get_headers = ngx.req.get_headers
local optionIsOn = function (options) return options == "on" and true or false end
loghack=optionIsOn(loghack)
--载入socket.lua用于发送log到独立syslog服务器。
local logger = require "socket"
if loghack then


if not logger.initted() then
local ok, err = logger.init{
--host = '192.168.0.1',
host = 'logserver.local',
port = 514,
sock_type = "udp", --udp协议
flush_limit = 1, --立即发送
--drop_limit = 5678,
pool_size = 100,--连接池大小
}
if not ok then
ngx.log(ngx.ERR, "failed to initialize the logger: ",
err)
return
end
end
end


logpath = logdir
rulepath = RulePath
logtofile = optionIsOn(logtofile)
logtoserver = optionIsOn(logtoserver)
UrlDeny = optionIsOn(UrlDeny)
PostCheck = optionIsOn(postMatch)
CookieCheck = optionIsOn(cookieMatch)
WhiteCheck = optionIsOn(whiteModule)
PathInfoFix = optionIsOn(PathInfoFix)
attacklog = optionIsOn(attacklog)
hackipdeny = optionIsOn(hackipdeny)
CCDeny = optionIsOn(CCDeny)
Redirect=optionIsOn(Redirect)
local file = io.open('config')

function getClientIp()
IP = ngx.var.remote_addr
if IP == nil then
Expand All @@ -28,19 +61,38 @@ function write(logfile,msg)
fd:flush()
fd:close()
end

function swrite(msg)
--保存警告等级要高于nginx error_log的默认等级。
ngx.log(ngx.CRIT,msg)



end

function log(method,url,data,ruletag)
if attacklog then
local realIp = getClientIp()
local ua = ngx.var.http_user_agent
local servername=ngx.var.server_name
local time=ngx.localtime()
if ua then
line = realIp.." ["..time.."] \""..method.." "..servername..url.."\" \""..data.."\" \""..ua.."\" \""..ruletag.."\"\n"
else
line = realIp.." ["..time.."] \""..method.." "..servername..url.."\" \""..data.."\" - \""..ruletag.."\"\n"
if ua == nil then
ua="null"
end
local servername=ngx.var.host
local time=ngx.localtime()
if logtofile then
local filename = logpath..'/'..servername.."_"..ngx.today().."_sec.log"
line=realIp.." ["..time.."]".."\""..method.." "..servername..url.."\""..data.."\""..ua.."\""..ruletag.."\"".."\n"
write(filename,line)
end
if logtoserver then
line=realIp.."\""..method.." "..servername..url.."\""..data.."\""..ua.."\""..ruletag.."\""
--line="lua_waf:"..line
swrite(line)
end
--发送ip到独立syslog服务器。
if loghack then local bytes, err = logger.log(getClientIp()) end
--只要log记录,说明被攻击,利用denyhackip将ip记录。
if hackipdeny then denyhackip(0) end
end
end
------------------------------------规则读取函数-------------------------------------------------------------------
Expand Down Expand Up @@ -78,21 +130,35 @@ function whiteurl()
if WhiteCheck then
if wturlrules ~=nil then
for _,rule in pairs(wturlrules) do
if ngxmatch(ngx.var.uri,rule,"isjo") then
--针对site:开始的进行域名匹配。增加白名单用处。
local sitemod,_=string.find(rule,"site:")
if sitemod==1 then
rule=string.gsub(rule,"site:","",1)
--调试whiteurl
--if ngx.var.host=='domino.cqhrss.gov.cn' then
-- log('debug',ngx.var.uri,"",rule)
--end
if ngxmatch(ngx.var.host..ngx.var.uri,rule,"isjo") then
return true
end
end
else
if ngxmatch(ngx.var.uri,rule,"isjo") then
return true
end
end
end
end
end
return false
end

function fileExtCheck(ext)
local items = Set(black_fileExt)
ext=string.lower(ext)
if ext then
for rule in pairs(items) do
if ngx.re.match(ext,rule,"isjo") then
log('POST',ngx.var.request_uri,"-","file attack with ext "..ext)
for rule,_ in pairs(items) do
if ngxmatch(ext,rule,"isjo") then
log('POST',ngx.var.request_uri,"-","file attack with ext "..ext)
say_html()
end
end
Expand Down Expand Up @@ -184,17 +250,25 @@ end
function denycc()
if CCDeny then
local uri=ngx.var.uri
CCcount=tonumber(string.match(CCrate,'(.*)/'))
CCseconds=tonumber(string.match(CCrate,'/(.*)'))
local m, err = ngx.re.match(CCrate,'([0-9]+)/([0-9]+)/([0-9]+)')
local CCcount=tonumber(m[1]) --计数器上限
local CCseconds=tonumber(m[2]) --计时器
local CClimits=tonumber(m[3]) --阻止访问时间
local token = getClientIp()..uri
local limit = ngx.shared.limit
local req,_=limit:get(token)
local req,_=limit:get(token) --计数器当前值

if req then
if req > CCcount then
ngx.exit(503)
ngx.exit(404)
return true
else
limit:incr(token,1)
if req == CCcount then limit:set(token,CCcount+1,CClimits) end

limit:incr(token,1)
--调试在syslog日志中查看
--swrite('计数器:'..token..'当前计数器'..req..'阻止访问时间:'..CClimits)

end
else
limit:set(token,1,CCseconds)
Expand All @@ -203,6 +277,41 @@ function denycc()
return false
end

--chk为1表示检测值,不增加,不创建,返回检测结果。
function denyhackip(chk)
if hackipdeny then

local m, err = ngx.re.match(hackrate,'([0-9]+)/([0-9]+)/([0-9]+)')
local hicount=tonumber(m[1]) --计数器上限
local hiseconds=tonumber(m[2]) --计时器
local hilimits=tonumber(m[3]) --阻止访问时间
local token = "hackip"..getClientIp()
local limit = ngx.shared.limit
local req,_=limit:get(token) --计数器当前值
if req then
if req > hicount then
ngx.exit(404)
return true
else

if req == hicount then
limit:set(token,hicount+1,hilimits)
swrite("ip:"..getClientIp().."因攻击被暂停访问"..hilimits.."秒。")
end
if chk ~=1 then limit:incr(token,1) end
--调试在syslog日志中查看
--swrite("计数器:"..token.."检测状态:"..chk.."当前计数器"..req.."阻止访问时间:"..hilimits)


end
else
if chk ~=1 then limit:set(token,1,hiseconds) end

end
end
return false
end

function get_boundary()
local header = get_headers()["content-type"]
if not header then
Expand Down
Loading