转自: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

  1. RulePath = "/data/mypro/ngx_lua/waf/wafconf/"
  2. attacklog = "on"
  3. logdir = "/usr/local/openresty/nginx/logs"
  4. UrlDeny="on"
  5. Redirect="on"
  6. CookieMatch="on"
  7. postMatch="on"
  8. whiteModule="on"
  9. ipWhitelist={}
  10. ipBlocklist={"1.0.0.1"}
  11. CCDeny="off"
  12. CCrate="100/60"
  13. html=[[Please go away~~ ]]

init.lua

  1. require 'config'
  2. local match = string.match
  3. local ngxmatch=ngx.re.match
  4. local unescape=ngx.unescape_uri
  5. local get_headers = ngx.req.get_headers
  6. local optionIsOn = function (options) return options == "on" and true or false end
  7. logpath = logdir
  8. rulepath = RulePath
  9. UrlDeny = optionIsOn(UrlDeny)
  10. PostCheck = optionIsOn(postMatch)
  11. CookieCheck = optionIsOn(cookieMatch)
  12. WhiteCheck = optionIsOn(whiteModule)
  13. PathInfoFix = optionIsOn(PathInfoFix)
  14. attacklog = optionIsOn(attacklog)
  15. CCDeny = optionIsOn(CCDeny)
  16. Redirect=optionIsOn(Redirect)
  17. function getClientIp()
  18. IP = ngx.req.get_headers()["X-Real-IP"]
  19. if IP == nil then
  20. IP = ngx.var.remote_addr
  21. end
  22. if IP == nil then
  23. IP = "unknown"
  24. end
  25. return IP
  26. end
  27. function write(logfile,msg)
  28. local fd = io.open(logfile,"ab")
  29. if fd == nil then return end
  30. fd:write(msg)
  31. fd:flush()
  32. fd:close()
  33. end
  34. function log(method,url,data,ruletag)
  35. if attacklog then
  36. local realIp = getClientIp()
  37. local ua = ngx.var.http_user_agent
  38. local servername=ngx.var.server_name
  39. local time=ngx.localtime()
  40. if ua then
  41. line = realIp.." ["..time.."] \""..method.." "..servername..url.."\" \""..data.."\" \""..ua.."\" \""..ruletag.."\"\n"
  42. else
  43. line = realIp.." ["..time.."] \""..method.." "..servername..url.."\" \""..data.."\" - \""..ruletag.."\"\n"
  44. end
  45. local filename = logpath..'/'..servername.."_"..ngx.today().."_sec.log"
  46. write(filename,line)
  47. end
  48. end
  49. ------------------------------------规则读取函数-------------------------------------------------------------------
  50. function read_rule(var)
  51. file = io.open(rulepath..'/'..var,"r")
  52. if file==nil then
  53. return
  54. end
  55. t = {}
  56. for line in file:lines() do
  57. table.insert(t,line)
  58. end
  59. file:close()
  60. return(t)
  61. 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')

  1. function say_html()
  2. if Redirect then
  3. ngx.header.content_type = "text/html"
  4. ngx.say(html)
  5. ngx.exit()
  6. end
  7. end
  8.  
  9. function whiteurl()
  10. if WhiteCheck then
  11. if wturlrules ~=nil then
  12. for _,rule in pairs(wturlrules) do
  13. if ngxmatch(ngx.var.request_uri,rule,"imjo") then
  14. return true
  15. end
  16. end
  17. end
  18. end
  19. return false
  20. end
  21.  
  22. function args()
  23. for _,rule in pairs(argsrules) do
  24. local args = ngx.req.get_uri_args()
  25. for key, val in pairs(args) do
  26. if type(val)=='table' then
  27. if val == false then
  28. data=table.concat(val, " ")
  29. end
  30. else
  31. data=val
  32. end
  33. if data and type(data) ~= "boolean" and rule ~="" and ngxmatch(unescape(data),rule,"imjo") then
  34. log('GET',ngx.var.request_uri,"-",rule)
  35. say_html()
  36. return true
  37. end
  38. end
  39. end
  40. return false
  41. end
  42.  
  43. function url()
  44. if UrlDeny then
  45. for _,rule in pairs(urlrules) do
  46. if rule ~="" and ngxmatch(ngx.var.request_uri,rule,"imjo") then
  47. log('GET',ngx.var.request_uri,"-",rule)
  48. say_html()
  49. return true
  50. end
  51. end
  52. end
  53. return false
  54. end
  55.  
  56. function ua()
  57. local ua = ngx.var.http_user_agent
  58. if ua ~= nil then
  59. for _,rule in pairs(uarules) do
  60. if rule ~="" and ngxmatch(ua,rule,"imjo") then
  61. log('UA',ngx.var.request_uri,"-",rule)
  62. say_html()
  63. return true
  64. end
  65. end
  66. end
  67. return false
  68. end
  69. function body(data)
  70. for _,rule in pairs(postrules) do
  71. if rule ~="" and data~="" and ngxmatch(unescape(data),rule,"imjo") then
  72. log('POST',ngx.var.request_uri,data,rule)
  73. say_html()
  74. return true
  75. end
  76. end
  77. return false
  78. end
  79. function cookie()
  80. local ck = ngx.var.http_cookie
  81. if CookieCheck and ck then
  82. for _,rule in pairs(ckrules) do
  83. if rule ~="" and ngxmatch(ck,rule,"imjo") then
  84. log('Cookie',ngx.var.request_uri,"-",rule)
  85. say_html()
  86. return true
  87. end
  88. end
  89. end
  90. return false
  91. end
  92.  
  93. function denycc()
  94. if CCDeny then
  95. local uri=ngx.var.uri
  96. CCcount=tonumber(string.match(CCrate,'(.*)/'))
  97. CCseconds=tonumber(string.match(CCrate,'/(.*)'))
  98. local token = getClientIp()..uri
  99. local limit = ngx.shared.limit
  100. local req,_=limit:get(token)
  101. if req then
  102. if req > CCcount then
  103. ngx.exit()
  104. return true
  105. else
  106. limit:incr(token,)
  107. end
  108. else
  109. limit:set(token,,CCseconds)
  110. end
  111. end
  112. return false
  113. end
  114.  
  115. function get_boundary()
  116. local header = get_headers()["content-type"]
  117. if not header then
  118. return nil
  119. end
  120.  
  121. if type(header) == "table" then
  122. header = header[]
  123. end
  124.  
  125. local m = match(header, ";%s*boundary=\"([^\"]+)\"")
  126. if m then
  127. return m
  128. end
  129.  
  130. return match(header, ";%s*boundary=([^\",;]+)")
  131. end
  132.  
  133. function whiteip()
  134. if next(ipWhitelist) ~= nil then
  135. for _,ip in pairs(ipWhitelist) do
  136. if getClientIp()==ip then
  137. return true
  138. end
  139. end
  140. end
  141. return false
  142. end
  143.  
  144. function blockip()
  145. if next(ipBlocklist) ~= nil then
  146. for _,ip in pairs(ipBlocklist) do
  147. if getClientIp()==ip then
  148. ngx.exit()
  149. return true
  150. end
  151. end
  152. end
  153. return false
  154. end

waf.lua

  1. local content_length=tonumber(ngx.req.get_headers()['content-length'])
  2. local method=ngx.req.get_method()
  3. if whiteip() then
  4. elseif blockip() then
  5. elseif denycc() then
  6. elseif ngx.var.http_Acunetix_Aspect then
  7. ngx.exit()
  8. elseif ngx.var.http_X_Scan_Memo then
  9. ngx.exit()
  10. elseif whiteurl() then
  11. elseif ua() then
  12. elseif url() then
  13. elseif args() then
  14. elseif cookie() then
  15. elseif PostCheck then
  16. if method=="POST" then
  17. local boundary = get_boundary()
  18. if boundary then
  19. local len = string.len
  20. local sock, err = ngx.req.socket()
  21. if not sock then
  22. return
  23. end
  24. ngx.req.init_body( * )
  25. sock:settimeout()
  26. local content_length = nil
  27. content_length=tonumber(ngx.req.get_headers()['content-length'])
  28. local chunk_size =
  29. if content_length < chunk_size then
  30. chunk_size = content_length
  31. end
  32. local size =
  33. while size < content_length do
  34. local data, err, partial = sock:receive(chunk_size)
  35. data = data or partial
  36. if not data then
  37. return
  38. end
  39. ngx.req.append_body(data)
  40. if body(data) then
  41. return true
  42. end
  43. size = size + len(data)
  44. local less = content_length - size
  45. if less < chunk_size then
  46. chunk_size = less
  47. end
  48. end
  49. ngx.req.finish_body()
  50. else
  51. ngx.req.read_body()
  52. local args = ngx.req.get_post_args()
  53. if not args then
  54. return
  55. end
  56. for key, val in pairs(args) do
  57. if type(val) == "table" or val == false then
  58. data=table.concat(val, ", ")
  59. else
  60. data=val
  61. end
  62. if data and type(data) ~= "boolean" and body(data) then
  63. return true
  64. end
  65. end
  66. end
  67. end
  68. else
  69. return
  70. end

在nginx.conf的http段添加

  1. lua_package_path "/usr/local/nginx/conf/waf/?.lua";
  2. lua_shared_dict limit 10m;
  3. init_by_lua_file /usr/local/nginx/conf/waf/init.lua;
  4. access_by_lua_file /usr/local/nginx/conf/waf/waf.lua;

重启nginx

部署完毕可以尝试如下命令:

  1. curl http://xxxx/test.php?id=../etc/passwd
  2. 返回"Please go away~~"字样,说明规则生效。

ngx_lua模块学习示例之waf的更多相关文章

  1. Day5 - Python基础5 常用模块学习

    Python 之路 Day5 - 常用模块学习   本节大纲: 模块介绍 time &datetime模块 random os sys shutil json & picle shel ...

  2. 大数据下基于Tensorflow框架的深度学习示例教程

    近几年,信息时代的快速发展产生了海量数据,诞生了无数前沿的大数据技术与应用.在当今大数据时代的产业界,商业决策日益基于数据的分析作出.当数据膨胀到一定规模时,基于机器学习对海量复杂数据的分析更能产生较 ...

  3. python中confIgparser模块学习

    python中configparser模块学习 ConfigParser模块在python中用来读取配置文件,配置文件的格式跟windows下的ini配置文件相似,可以包含一个或多个节(section ...

  4. OpenResty之ngx_lua模块的加密接口

    原文: ngx_Lua模块中的加密api接口 ngx.crc32_short digest = ngx.crc32_short(str) 该方法主要是计算给定字符串 str 的循环校验码(Cyclic ...

  5. osg学习示例之遇到问题四骨骼动画编译osgCal

    osg学习示例之遇到问题四骨骼动画编译osgCal 转自:http://blog.csdn.net/wuwangrun/article/details/8239451 今天学到书<OpenSce ...

  6. 不学就吃亏的underscorejs类库学习示例 ——(集合篇)

    underscorejs是一个很不错的类库,我的很多项目都引用了这个类库,的确可以带来很多方便. 记得我当初学的时候,看underscorejs的api是看的一知半解的,甚至不明白api里的conte ...

  7. zigbee学习:示例程序SampleApp中按键工作流程

    zigbee学习:示例程序SampleApp中按键工作流程 本文博客链接:http://blog.csdn.net/jdh99,作者:jdh,转载请注明. 环境: 主机:WIN7 开发环境:IAR8. ...

  8. zigbee学习:示例程序SampleApp中通讯流程

    zigbee学习:示例程序SampleApp中通讯流程 本文博客链接:http://blog.csdn.net/jdh99,作者:jdh,转载请注明. 参考链接: http://wjf88223.bl ...

  9. # nodejs模块学习: express 解析

    # nodejs模块学习: express 解析 nodejs 发展很快,从 npm 上面的包托管数量就可以看出来.不过从另一方面来看,也是反映了 nodejs 的基础不稳固,需要开发者创造大量的轮子 ...

随机推荐

  1. eclipse插件之easyshell

    在eclipse marketplace可以找到这个插件,名字就是easyshell,下载安装完以后,可以通过配置快捷键实现: enjoy it.

  2. BLDC之六种霍尔检测换相排序表

    /* 1 BLDC 的六种霍尔换相排列表 2 包含正反转 */ //#define BLDC_HALL_CAB //-- //#define BLDC_HALL_CBA //#define BLDC_ ...

  3. Struts完美解决i18n问题

    所谓的i18n问题指的是(软件的)国际化问题,简单来讲就是使我们的软件可以让世界使用任何语言的人们都能使用,软件自身会根据语言环境的不同进行自动配置,如果你是中文环境那界面以中文显示,如果是英文环境就 ...

  4. 静态库与动态库的制作以及程序的动态函数库解析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 ...

  5. Python 命令行输出的颜色设置

    Console上运行的python程序,有没有办法让print输出的文本可以显示不同的颜色? 这个其实跟python无关,跟具体所用console的类型有关系,不同的类型对应不同的控制码,如果是ans ...

  6. Global Times 单词(日常收集)

    1. 2013-09-09 windfall 英[ˈwɪndfɔ:l] 美[ˈwɪndˌfɔl] n.意外之财:被风吹落的果子:意外的收获 eg:Only half made any attempt ...

  7. Session 简单购物车

    package session.test; import java.io.IOException; import java.io.PrintWriter; import java.util.Linke ...

  8. PHP LDAP class for Active Directory

    A class for PHP to talk to Active Directory through LDAP.http://sourceforge.net/projects/adldap/

  9. Solr 4.0部署

    http://www.blogjava.net/xiaohuzi2008/archive/2012/12/03/392373.html

  10. JavaScript 对象与数组参考大全

    http://www.cnblogs.com/meil/archive/2006/06/28/437527.html本文列举了各种JavaScript对象与数组,同时包括对上述每一对象或数组所完成工作 ...