waf

时间:Sept. 27, 2017 分类:

目录:

waf

waf简介

waf是一个web防火墙,用于七层应用层进行防护,防止一些SQL注入等请求。waf是基于对HTTP/HTTPS流量的双向解码分析,应对HTTP/HTTPS应用中的各类安全威胁,如SQL注入、XSS、目录遍历、命令执行等。WAF一句话描述,就是解析HTTP请求(协议解析模块),规则检测(规则模块),做不同的防御动作(动作模块),并将防御过程(日志模块)记录下来。

在web1.0时代,那个时候并没有waf,随着web2.0技术的日益发展,其中的攻击也层出不穷。比如应用层的SQL注入、XSS、文件包含等web漏洞。由于传统的防火墙是放在网关处,不能很好的防御此漏洞,所以WAF就应运而生。waf是部署在web服务器集群的前端,对Web服务器进行防护。

本文档waf是通过lua实现,参考githua链接

waf的总体检测思路:

当用户访问到nginx时,waf首先获取用户的ip,uri,referer,useragent,cookie,args,post,method,header信息。将获取到的信息依次传给上述功能的函数,如ip规则,在ip规则中,循环到所有的ip规则,如果匹配到ip则根据规则的处理方式来进行处理,匹配到之后不继续匹配后续规则。需要开启的功能依次在主函数中调用即可,顺序也可根据实际场景来确定最合适的顺序。

实现功能

  • 防止sql注入,本地包含,部分溢出,fuzzing测试,xss, ssrf等web攻击
  • 防止svn/备份之类文件泄漏
  • 防止ApacheBench之类压力测试工具的攻击
  • 屏蔽常见的扫描黑客工具,扫描器
  • 屏蔽异常的网络请求
  • 屏蔽图片附件类目录php执行权限
  • 防止webshell上传
  • 接口频率限制
  • 对键值进行限制

部署

我这边使用了openresty,是因为openresty自带lua支持和ngx_lua。

是一个基于Nginx与Lua的高性能Web平台,其内部集成了大量精良的Lua库、第三方模块以及大多数的依赖项。

nginx_lua的处理流程

解压释放

[root@6865188c83d0 conf.d]# pwd
/opt/openresty/nginx/conf/conf.d
[root@6865188c83d0 conf.d]# ll
total 28
-rw-r--r-- 1 root root  632 Aug 28 16:57 blog.whysdomain.com.conf
-rw-r--r-- 1 root root  605 Sep 12 00:24 cmdb.whysdomain.com.conf
-rw-r--r-- 1 root root  525 Aug 26 23:11 home.whysdomain.com.conf
-rw-r--r-- 1 root root  496 Aug 13 23:54 image.whysdomain.com.conf
-rw-r--r-- 1 root root  134 Aug 28 16:55 upstream.whysdomain.com.conf
drwxr-xr-x 5 root root 4096 Sep 15 15:55 waf
-rw-r--r-- 1 root root 2095 Sep  3 17:51 www.whysdomain.com.conf

目录结构

[root@6865188c83d0 conf.d]# tree waf/
waf/
├── config.lua                          主配置文件               
├── init.lua                            主程序
├── install.sh
├── log.lua                             
├── README.md
├── wafconf
│   ├── args                            匹配规则,用于过滤get请求参数进行过滤
│   ├── Block_iplist_lan.txt
│   ├── Block_iplist.txt
│   ├── cookie
│   ├── post                            匹配规则,用户过滤post请求参数进行过滤
│   ├── url                             匹配规则,用于过滤get请求url
│   ├── user-agent                      匹配规则,对user-agent进行匹配
│   ├── White_iplist_lan.txt
│   ├── White_iplist.txt
│   └── whiteurl                        匹配规则,白名单里的url不进行过滤
└── waf.lua

配置nginx

在nginx.conf配置文件的http模块添加一下内容

    lua_need_request_body on;
    lua_package_path "/opt/openresty/nginx/conf/conf.d/waf/?.lua;";
    lua_shared_dict limit 50m;
    init_by_lua_file  /opt/openresty/nginx/conf/conf.d/waf/init.lua;
    access_by_lua_file /opt/openresty/nginx/conf/conf.d/waf/waf.lua;
    log_by_lua_file  /opt/openresty/nginx/conf/conf.d/waf/log.lua;

config.lua

waf="on"                                                                        -- waf开关
RulePath = "/opt/openresty/nginx/conf/conf.d/waf/wafconf/"                      -- 规则路径
attacklog = "on"                                                                -- 日志开关
logdir = "/data/log/nginx/"                                                     -- 日志路径
UrlDeny="on"                                                                    -- url恶意拦截
Redirect="on"                                                                   -- 拦截开关
CookieMatch="on"                                                                -- cookie恶意拦截
postMatch="on"                                                                  -- post恶意拦截
Args="on"                                                                       -- get参数恶意拦截(使用正则消耗性能大)
dataMatch ="on"                                                                 -- post下的web漏洞恶意拦截(使用正则消耗性能大)
whiteModule="on"                                                                -- url白名单
black_fileExt={"php","jsp"}                                                     -- 上传图片恶意拦截
Content_Length="104857600"                                                      -- body过大拦截

CCDeny="on"                                                                     -- cc拦截(获取url进行频率限制)
CCrate="1000/60"                                                                -- 次数/时间(单位秒)

Cookie_CCDeny="off"                                                             -- cookie cc拦截(只对通过浏览器访问的用户有效)
Cookie_CCrate="800/60"                                                          -- 次数/时间(单位秒)

Status_CCDeny="on"                                                              -- 状态码拦截(现只对404进行频率拦截)
CCrate_404="30/60"                                                              -- 次数/时间(单位秒)

rule_1_denycc="off"                                                             -- 接口频率拦截(一共可提供三个接口限制)
rule_1={"phone_number","password","60","600","ua","ip"}                         -- {"key","key","次数","频率","ua","ip"},如果只有一个key ,另一个可以 "" 表示,ua/ip,分别表示是否进行该维度判断,如果不加入,可以为使用""表示。 600秒60次
rule_2_denycc="off"
rule_2={"a","b","3","60","ua","ip"}
rule_3_denycc="off"
rule_3={"e","a","1","60","ua","ip"}

rule_1_denycc_value="off"                                                       --接口频率拦截
rule_1_value={"method","xingeToken","60","600","ua","ip","login_by_phone"}      --{"key","key","次数","频率","ua","ip","value"},使用value值拦截。

rule_1_block="off"                                                              -- 键值拦截(一共提供两个接口限制)
rule_block_1={"userId",{"25507787"}}                                            -- {"key",{"value"}},如{"userId",{"54361315"}},对54361315进行限制访问。
rule_2_block="off"
rule_block_2={"b",{"bbb"}}

Url_CCDeny="off"
Url_CCrate="3000/60"
html=[[
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="Content-Language" content="zh-cn" />
<title>网站防火墙</title>
</head>
<body>
<h3 align="center"> 当前访问可能对网站安全造成威胁,已被网站防火墙拦截!!!
</body>
</html>
]]
cchtml=[[
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="Content-Language" content="zh-cn" />
<title>网站防火墙</title>
</head>
<body>
<h3 align="center"> 当前访问过于频繁,请稍后再试!!!
</body>
</html>
]]
bkiphtml=[[
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="Content-Language" content="zh-cn" />
<title>网站防火墙</title>
</head>
<body>
<h3 align="center"> IP异常禁止访问!!!
</body>
</html>
]]
clhtml=[[
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="Content-Language" content="zh-cn" />
<title>网站防火墙</title>
</head>
<body>
<h3 align="center"> 文件过大禁止上传!!!
</body>
</html>
]]

部署到线上可以看到还是有效果的进行了防护。

[root@6865188c83d0 nginx]# cat www.whysdomain.com.sec.log.2017-09-15 
140.205.225.203-==-[2017-09-15 06:08:33]-==-"www.whysdomain.com"-==-"GET www.whysdomain.com/phpmyadmin/"-==-"-"-==-"Python-urllib/2.6"-==-"(phpmyadmin|jmx-console|jmxinvokerservlet)"-==-"html"
140.205.225.203-==-[2017-09-15 06:08:33]-==-"www.whysdomain.com"-==-"GET www.whysdomain.com/phpmyadmin/"-==-"-"-==-"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;Alibaba.Security.Heimdall.5448812.phpmyadmin_login_weak)"-==-"(phpmyadmin|jmx-console|jmxinvokerservlet)"-==-"html"
140.205.225.203-==-[2017-09-15 06:08:33]-==-"www.whysdomain.com"-==-"GET www.whysdomain.com/phpmyadmin/"-==-"-"-==-"Python-urllib/2.6"-==-"(phpmyadmin|jmx-console|jmxinvokerservlet)"-==-"html"
140.205.225.203-==-[2017-09-15 06:08:34]-==-"www.whysdomain.com"-==-"GET www.whysdomain.com/phpmyadmin/"-==-"-"-==-"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;Alibaba.Security.Heimdall.5448812.phpmyadmin_login_weak)"-==-"(phpmyadmin|jmx-console|jmxinvokerservlet)"-==-"html"
140.205.225.203-==-[2017-09-15 06:08:34]-==-"www.whysdomain.com"-==-"GET www.whysdomain.com/phpmyadmin/"-==-"-"-==-"Python-urllib/2.6"-==-"(phpmyadmin|jmx-console|jmxinvokerservlet)"-==-"html"
140.205.225.203-==-[2017-09-15 06:08:34]-==-"www.whysdomain.com"-==-"GET www.whysdomain.com/phpmyadmin/"-==-"-"-==-"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;Alibaba.Security.Heimdall.5448812.phpmyadmin_login_weak)"-==-"(phpmyadmin|jmx-console|jmxinvokerservlet)"-==-"html"
140.205.225.203-==-[2017-09-15 06:08:34]-==-"www.whysdomain.com"-==-"GET www.whysdomain.com/phpmyadmin/"-==-"-"-==-"Python-urllib/2.6"-==-"(phpmyadmin|jmx-console|jmxinvokerservlet)"-==-"html"
140.205.225.203-==-[2017-09-15 06:08:35]-==-"www.whysdomain.com"-==-"GET www.whysdomain.com/phpmyadmin/"-==-"-"-==-"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;Alibaba.Security.Heimdall.5448812.phpmyadmin_login_weak)"-==-"(phpmyadmin|jmx-console|jmxinvokerservlet)"-==-"html"
140.205.225.203-==-[2017-09-15 06:08:35]-==-"www.whysdomain.com"-==-"GET www.whysdomain.com/phpmyadmin/"-==-"-"-==-"Python-urllib/2.6"-==-"(phpmyadmin|jmx-console|jmxinvokerservlet)"-==-"html"
140.205.225.203-==-[2017-09-15 06:08:35]-==-"www.whysdomain.com"-==-"GET www.whysdomain.com/phpmyadmin/"-==-"-"-==-"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;Alibaba.Security.Heimdall.5448812.phpmyadmin_login_weak)"-==-"(phpmyadmin|jmx-console|jmxinvokerservlet)"-==-"html"
140.205.225.203-==-[2017-09-15 06:08:35]-==-"www.whysdomain.com"-==-"GET www.whysdomain.com/phpmyadmin/"-==-"-"-==-"Python-urllib/2.6"-==-"(phpmyadmin|jmx-console|jmxinvokerservlet)"-==-"html"
140.205.225.203-==-[2017-09-15 06:08:35]-==-"www.whysdomain.com"-==-"GET www.whysdomain.com/phpmyadmin/"-==-"-"-==-"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;Alibaba.Security.Heimdall.5448812.phpmyadmin_login_weak)"-==-"(phpmyadmin|jmx-console|jmxinvokerservlet)"-==-"html"
140.205.225.203-==-[2017-09-15 06:08:36]-==-"www.whysdomain.com"-==-"GET www.whysdomain.com/phpmyadmin/"-==-"-"-==-"Python-urllib/2.6"-==-"(phpmyadmin|jmx-console|jmxinvokerservlet)"-==-"html"
140.205.225.203-==-[2017-09-15 06:08:36]-==-"www.whysdomain.com"-==-"GET www.whysdomain.com/phpmyadmin/"-==-"-"-==-"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;Alibaba.Security.Heimdall.5448812.phpmyadmin_login_weak)"-==-"(phpmyadmin|jmx-console|jmxinvokerservlet)"-==-"html"
140.205.225.203-==-[2017-09-15 06:08:36]-==-"www.whysdomain.com"-==-"GET www.whysdomain.com/phpmyadmin/"-==-"-"-==-"Python-urllib/2.6"-==-"(phpmyadmin|jmx-console|jmxinvokerservlet)"-==-"html"
140.205.225.203-==-[2017-09-15 06:08:36]-==-"www.whysdomain.com"-==-"GET www.whysdomain.com/phpmyadmin/"-==-"-"-==-"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;Alibaba.Security.Heimdall.5448812.phpmyadmin_login_weak)"-==-"(phpmyadmin|jmx-console|jmxinvokerservlet)"-==-"html"
140.205.225.203-==-[2017-09-15 06:08:36]-==-"www.whysdomain.com"-==-"GET www.whysdomain.com/phpmyadmin/"-==-"-"-==-"Python-urllib/2.6"-==-"(phpmyadmin|jmx-console|jmxinvokerservlet)"-==-"html"
140.205.225.203-==-[2017-09-15 06:08:37]-==-"www.whysdomain.com"-==-"GET www.whysdomain.com/phpmyadmin/"-==-"-"-==-"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;Alibaba.Security.Heimdall.5448812.phpmyadmin_login_weak)"-==-"(phpmyadmin|jmx-console|jmxinvokerservlet)"-==-"html"
140.205.225.203-==-[2017-09-15 06:08:37]-==-"www.whysdomain.com"-==-"GET www.whysdomain.com/phpmyadmin/"-==-"-"-==-"Python-urllib/2.6"-==-"(phpmyadmin|jmx-console|jmxinvokerservlet)"-==-"html"
140.205.225.203-==-[2017-09-15 06:08:37]-==-"www.whysdomain.com"-==-"GET www.whysdomain.com/phpmyadmin/"-==-"-"-==-"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;Alibaba.Security.Heimdall.5448812.phpmyadmin_login_weak)"-==-"(phpmyadmin|jmx-console|jmxinvokerservlet)"-==-"html"
140.205.225.203-==-[2017-09-15 06:21:06]-==-"www.whysdomain.com"-==-"POST www.whysdomain.com/showcase/integration/saveGangster.action"-==-"%{(#_='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#a=12302938).(#b=3123812+#a).(#cmd=' echo aliyun_'+#a+#b).(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}"-==-"Python-urllib/2.6"-==-"java\.lang"-==-"html"
140.205.225.203-==-[2017-09-15 06:21:06]-==-"www.whysdomain.com"-==-"POST www.whysdomain.com/struts2-showcase/integration/saveGangster.action"-==-"%{(#_='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#a=12302938).(#b=3123812+#a).(#cmd=' echo aliyun_'+#a+#b).(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}"-==-"Python-urllib/2.6"-==-"java\.lang"-==-"html"
140.205.225.203-==-[2017-09-15 06:21:06]-==-"www.whysdomain.com"-==-"POST www.whysdomain.com/integration/saveGangster.action"-==-"%{(#_='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#a=12302938).(#b=3123812+#a).(#cmd=' echo aliyun_'+#a+#b).(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}"-==-"Python-urllib/2.6"-==-"java\.lang"-==-"html"

如果测试也可以直接接参数a.php?a=a select a from b

源代码解读

更多可以参考http://www.cnblogs.com/wangxusummer/tag/Lua/