ngx_lua模块学习示例之waf
转自:http://www.tuicool.com/articles/FbQ3ymB
WAF的主要功能为:
- ip黑白名单
- url黑白名单
- useragent黑白名单
- referer黑白名单
- 常见web漏洞防护,如xss,sql注入等
- cc攻击防护
- 扫描器简单防护
- 其他你想要的功能
WAF的总体检测思路:
- 当用户访问到nginx时,waf首先获取用户的ip,uri,referer,useragent,,cookie,args,post,method,header信息。
- 将获取到的信息依次传给上述功能的函数,如ip规则,在ip规则中,循环到所有的ip规则,如果匹配到ip则根据规则的处理方式来进行处理,匹配到之后不继续匹配后续规则。
- 需要开启的功能依次在主函数中调用即可,顺序也可根据实际场景来确定最合适的顺序。
config.lua
- RulePath = "/data/mypro/ngx_lua/waf/wafconf/"
- attacklog = "on"
- logdir = "/usr/local/openresty/nginx/logs"
- UrlDeny="on"
- Redirect="on"
- CookieMatch="on"
- postMatch="on"
- whiteModule="on"
- ipWhitelist={}
- ipBlocklist={"1.0.0.1"}
- CCDeny="off"
- CCrate="100/60"
- html=[[Please go away~~ ]]
init.lua
- require 'config'
- local match = string.match
- local ngxmatch=ngx.re.match
- local unescape=ngx.unescape_uri
- local get_headers = ngx.req.get_headers
- local optionIsOn = function (options) return options == "on" and true or false end
- logpath = logdir
- rulepath = RulePath
- UrlDeny = optionIsOn(UrlDeny)
- PostCheck = optionIsOn(postMatch)
- CookieCheck = optionIsOn(cookieMatch)
- WhiteCheck = optionIsOn(whiteModule)
- PathInfoFix = optionIsOn(PathInfoFix)
- attacklog = optionIsOn(attacklog)
- CCDeny = optionIsOn(CCDeny)
- Redirect=optionIsOn(Redirect)
- function getClientIp()
- IP = ngx.req.get_headers()["X-Real-IP"]
- if IP == nil then
- IP = ngx.var.remote_addr
- end
- if IP == nil then
- IP = "unknown"
- end
- return IP
- end
- function write(logfile,msg)
- local fd = io.open(logfile,"ab")
- if fd == nil then return end
- fd:write(msg)
- fd:flush()
- fd:close()
- 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"
- end
- local filename = logpath..'/'..servername.."_"..ngx.today().."_sec.log"
- write(filename,line)
- end
- end
- ------------------------------------规则读取函数-------------------------------------------------------------------
- function read_rule(var)
- file = io.open(rulepath..'/'..var,"r")
- if file==nil then
- return
- end
- t = {}
- for line in file:lines() do
- table.insert(t,line)
- end
- file:close()
- return(t)
- end
local urlrules=read_rule('url')
local argsrules=read_rule('args')
local uarules=read_rule('user-agent')
local wturlrules=read_rule('whiteurl')
local postrules=read_rule('post')
local ckrules=read_rule('cookie')
- function say_html()
- if Redirect then
- ngx.header.content_type = "text/html"
- ngx.say(html)
- ngx.exit()
- end
- end
- function whiteurl()
- if WhiteCheck then
- if wturlrules ~=nil then
- for _,rule in pairs(wturlrules) do
- if ngxmatch(ngx.var.request_uri,rule,"imjo") then
- return true
- end
- end
- end
- end
- return false
- end
- function args()
- for _,rule in pairs(argsrules) do
- local args = ngx.req.get_uri_args()
- for key, val in pairs(args) do
- if type(val)=='table' then
- if val == false then
- data=table.concat(val, " ")
- end
- else
- data=val
- end
- if data and type(data) ~= "boolean" and rule ~="" and ngxmatch(unescape(data),rule,"imjo") then
- log('GET',ngx.var.request_uri,"-",rule)
- say_html()
- return true
- end
- end
- end
- return false
- end
- function url()
- if UrlDeny then
- for _,rule in pairs(urlrules) do
- if rule ~="" and ngxmatch(ngx.var.request_uri,rule,"imjo") then
- log('GET',ngx.var.request_uri,"-",rule)
- say_html()
- return true
- end
- end
- end
- return false
- end
- function ua()
- local ua = ngx.var.http_user_agent
- if ua ~= nil then
- for _,rule in pairs(uarules) do
- if rule ~="" and ngxmatch(ua,rule,"imjo") then
- log('UA',ngx.var.request_uri,"-",rule)
- say_html()
- return true
- end
- end
- end
- return false
- end
- function body(data)
- for _,rule in pairs(postrules) do
- if rule ~="" and data~="" and ngxmatch(unescape(data),rule,"imjo") then
- log('POST',ngx.var.request_uri,data,rule)
- say_html()
- return true
- end
- end
- return false
- end
- function cookie()
- local ck = ngx.var.http_cookie
- if CookieCheck and ck then
- for _,rule in pairs(ckrules) do
- if rule ~="" and ngxmatch(ck,rule,"imjo") then
- log('Cookie',ngx.var.request_uri,"-",rule)
- say_html()
- return true
- end
- end
- end
- return false
- end
- function denycc()
- if CCDeny then
- local uri=ngx.var.uri
- CCcount=tonumber(string.match(CCrate,'(.*)/'))
- CCseconds=tonumber(string.match(CCrate,'/(.*)'))
- local token = getClientIp()..uri
- local limit = ngx.shared.limit
- local req,_=limit:get(token)
- if req then
- if req > CCcount then
- ngx.exit()
- return true
- else
- limit:incr(token,)
- end
- else
- limit:set(token,,CCseconds)
- end
- end
- return false
- end
- function get_boundary()
- local header = get_headers()["content-type"]
- if not header then
- return nil
- end
- if type(header) == "table" then
- header = header[]
- end
- local m = match(header, ";%s*boundary=\"([^\"]+)\"")
- if m then
- return m
- end
- return match(header, ";%s*boundary=([^\",;]+)")
- end
- function whiteip()
- if next(ipWhitelist) ~= nil then
- for _,ip in pairs(ipWhitelist) do
- if getClientIp()==ip then
- return true
- end
- end
- end
- return false
- end
- function blockip()
- if next(ipBlocklist) ~= nil then
- for _,ip in pairs(ipBlocklist) do
- if getClientIp()==ip then
- ngx.exit()
- return true
- end
- end
- end
- return false
- end
waf.lua
- local content_length=tonumber(ngx.req.get_headers()['content-length'])
- local method=ngx.req.get_method()
- if whiteip() then
- elseif blockip() then
- elseif denycc() then
- elseif ngx.var.http_Acunetix_Aspect then
- ngx.exit()
- elseif ngx.var.http_X_Scan_Memo then
- ngx.exit()
- elseif whiteurl() then
- elseif ua() then
- elseif url() then
- elseif args() then
- elseif cookie() then
- elseif PostCheck then
- if method=="POST" then
- local boundary = get_boundary()
- if boundary then
- local len = string.len
- local sock, err = ngx.req.socket()
- if not sock then
- return
- end
- ngx.req.init_body( * )
- sock:settimeout()
- local content_length = nil
- content_length=tonumber(ngx.req.get_headers()['content-length'])
- local chunk_size =
- if content_length < chunk_size then
- chunk_size = content_length
- end
- local size =
- while size < content_length do
- local data, err, partial = sock:receive(chunk_size)
- data = data or partial
- if not data then
- return
- end
- ngx.req.append_body(data)
- if body(data) then
- return true
- end
- size = size + len(data)
- local less = content_length - size
- if less < chunk_size then
- chunk_size = less
- end
- end
- ngx.req.finish_body()
- else
- ngx.req.read_body()
- local args = ngx.req.get_post_args()
- if not args then
- return
- end
- for key, val in pairs(args) do
- if type(val) == "table" or val == false then
- data=table.concat(val, ", ")
- else
- data=val
- end
- if data and type(data) ~= "boolean" and body(data) then
- return true
- end
- end
- end
- end
- else
- return
- end
在nginx.conf的http段添加
- lua_package_path "/usr/local/nginx/conf/waf/?.lua";
- lua_shared_dict limit 10m;
- init_by_lua_file /usr/local/nginx/conf/waf/init.lua;
- access_by_lua_file /usr/local/nginx/conf/waf/waf.lua;
重启nginx
部署完毕可以尝试如下命令:
- curl http://xxxx/test.php?id=../etc/passwd
- 返回"Please go away~~"字样,说明规则生效。
ngx_lua模块学习示例之waf的更多相关文章
- Day5 - Python基础5 常用模块学习
Python 之路 Day5 - 常用模块学习 本节大纲: 模块介绍 time &datetime模块 random os sys shutil json & picle shel ...
- 大数据下基于Tensorflow框架的深度学习示例教程
近几年,信息时代的快速发展产生了海量数据,诞生了无数前沿的大数据技术与应用.在当今大数据时代的产业界,商业决策日益基于数据的分析作出.当数据膨胀到一定规模时,基于机器学习对海量复杂数据的分析更能产生较 ...
- python中confIgparser模块学习
python中configparser模块学习 ConfigParser模块在python中用来读取配置文件,配置文件的格式跟windows下的ini配置文件相似,可以包含一个或多个节(section ...
- OpenResty之ngx_lua模块的加密接口
原文: ngx_Lua模块中的加密api接口 ngx.crc32_short digest = ngx.crc32_short(str) 该方法主要是计算给定字符串 str 的循环校验码(Cyclic ...
- osg学习示例之遇到问题四骨骼动画编译osgCal
osg学习示例之遇到问题四骨骼动画编译osgCal 转自:http://blog.csdn.net/wuwangrun/article/details/8239451 今天学到书<OpenSce ...
- 不学就吃亏的underscorejs类库学习示例 ——(集合篇)
underscorejs是一个很不错的类库,我的很多项目都引用了这个类库,的确可以带来很多方便. 记得我当初学的时候,看underscorejs的api是看的一知半解的,甚至不明白api里的conte ...
- zigbee学习:示例程序SampleApp中按键工作流程
zigbee学习:示例程序SampleApp中按键工作流程 本文博客链接:http://blog.csdn.net/jdh99,作者:jdh,转载请注明. 环境: 主机:WIN7 开发环境:IAR8. ...
- zigbee学习:示例程序SampleApp中通讯流程
zigbee学习:示例程序SampleApp中通讯流程 本文博客链接:http://blog.csdn.net/jdh99,作者:jdh,转载请注明. 参考链接: http://wjf88223.bl ...
- # nodejs模块学习: express 解析
# nodejs模块学习: express 解析 nodejs 发展很快,从 npm 上面的包托管数量就可以看出来.不过从另一方面来看,也是反映了 nodejs 的基础不稳固,需要开发者创造大量的轮子 ...
随机推荐
- eclipse插件之easyshell
在eclipse marketplace可以找到这个插件,名字就是easyshell,下载安装完以后,可以通过配置快捷键实现: enjoy it.
- BLDC之六种霍尔检测换相排序表
/* 1 BLDC 的六种霍尔换相排列表 2 包含正反转 */ //#define BLDC_HALL_CAB //-- //#define BLDC_HALL_CBA //#define BLDC_ ...
- Struts完美解决i18n问题
所谓的i18n问题指的是(软件的)国际化问题,简单来讲就是使我们的软件可以让世界使用任何语言的人们都能使用,软件自身会根据语言环境的不同进行自动配置,如果你是中文环境那界面以中文显示,如果是英文环境就 ...
- 静态库与动态库的制作以及程序的动态函数库解析ldd;ldconfig与/etc/ld.so.conf
静态库的制作步骤: (1)gcc -c mylib.c -o mylib.o (2)ar rc libmylib.a mylib.o 动态库的制作步骤: gcc -shared mylib.c -o ...
- Python 命令行输出的颜色设置
Console上运行的python程序,有没有办法让print输出的文本可以显示不同的颜色? 这个其实跟python无关,跟具体所用console的类型有关系,不同的类型对应不同的控制码,如果是ans ...
- Global Times 单词(日常收集)
1. 2013-09-09 windfall 英[ˈwɪndfɔ:l] 美[ˈwɪndˌfɔl] n.意外之财:被风吹落的果子:意外的收获 eg:Only half made any attempt ...
- Session 简单购物车
package session.test; import java.io.IOException; import java.io.PrintWriter; import java.util.Linke ...
- PHP LDAP class for Active Directory
A class for PHP to talk to Active Directory through LDAP.http://sourceforge.net/projects/adldap/
- Solr 4.0部署
http://www.blogjava.net/xiaohuzi2008/archive/2012/12/03/392373.html
- JavaScript 对象与数组参考大全
http://www.cnblogs.com/meil/archive/2006/06/28/437527.html本文列举了各种JavaScript对象与数组,同时包括对上述每一对象或数组所完成工作 ...