开源框架openresty+nginx 实现web应用防火墙(WAF)

开源框架openresty+nginx 实现web应用防火墙(WAF)

 

1、简介
Web应用防火墙(Web Application Firewall, WAF),通过对HTTP(S)请求进行检测,识别并阻断SQL注入、跨站脚本攻击(Cross Site Scripting  xss)、网页木马上传、命令/代码注入、文件包含、敏感文件访问、第三方应用漏洞攻击、CC(挑战黑洞)攻击、恶意爬虫扫描、跨站请求伪造等攻击,保护Web服务安全稳定。

本文主要是通过春哥的开源框架openresty来实现WAF;

参考:https://github.com/openresty

 

2、架构
整体架构:春哥的openresty开源框架(该框架集成了nginx、lua、lua-nginx-module等模块),推荐使用该框架;

如果想使用原生的nginx、lua来搭建waf,请参阅  nginx lua lua-nginx-module构建web应用防火墙(waf)
3、实现功能
支持IP白名单和黑名单功能,直接将黑名单的IP访问拒绝。
支持URL白名单,将不需要过滤的URL进行定义。
支持User-Agent的过滤,匹配自定义规则中的条目,然后进行处理(返回403)。
支持CC攻击防护,单个URL指定时间的访问次数,超过设定值,直接返回403。
支持Cookie过滤,匹配自定义规则中的条目,然后进行处理(返回403)。
支持URL过滤,匹配自定义规则中的条目,如果用户请求的URL包含这些,返回403。
支持URL参数过滤,原理同上。
支持日志记录,将所有拒绝的操作,记录到日志中去。
日志记录为JSON格式,便于日志分析,例如使用ELKStack进行攻击日志收集、存储、搜索和展示。
4、安装包下载
提供了各种版本openresty,点击链接,去下载适合版本。

openresty-1.15.8.1.tar.gz

 

安装openresty

创建安装包目录并将下载的安装包上传至该目录(也可以直接通过wget命令直接下载)

解压 tar zxvf openresty-1.15.8.1.tar.gz

cd openresty-1.15.8.1

安装基本包

yum install -y readline-devel pcre-devel openssl-devel gcc gcc-c++ perl.x86_64

配置环境

 

编译 gmake

安装 gmake install

images

修改nginx.conf,测试是否安装成功

编辑nginx.conf

vi nginx.conf

启动nginx 一次执行下面代码段

images

 

 

 

 

 

 

 

关闭防火墙或者开放虚拟机防火墙端口,

这里为了方便,直接就关闭防火墙了,生产中必须采用开放防火墙端口的方式

systemctl stop firewalld

systemctl status firewalld

 

浏览器访问测试 http://10.10.91.23/hello

 

6、部署waf
下载waf包  https://github.com/unixhot/waf

可以使用wget,也可以下载到本地,让后上传到虚拟机

解压后,将waf复制到 /usr/local/openresty/nginx/conf/

cp -r waf /usr/local/openresty/nginx/conf/

修改Nginx的配置文件,加入以下配置。注意路径,同时WAF日志默认存放在/tmp/日期_waf.log

/usr/local/openresty/nginx/conf

vi nginx.conf

images

修改waf中的配置信息

cd /waf

vi config.lua


images

重启nginx即可测试

 

 

加上redis 自动加入黑名单设置。

cp  /usr/local/openresty/lualib/resty/redis.lua     /usr/local/openresty/nginx/conf/waf/

 

如果报如下错就是reids.lua 没有读取到。

 

images

编写链接Redis的Lua脚本 /usr/local/openresty/nginx/conf/waf/redis.lua

cat redis.lua

在nginx配置文件中添加以下location

 

 

images

4、验证
在浏览器输入ip/lua_redis
看能不能获取到刚才在redis添加的”123″ 这个key 并获取到他的值
如果能看到下图的内容表示可以访问redis

images

好的,准备工作已经准备好了,现在要来最终的Nginx+Lua+Redis自动封禁并解封IP了

三、Nginx+Lua+Redis
1、添加访问控制的Lua脚本
(此脚本需要改的只有下面的这一句,把redis的ip和端口替换一下即可
ok, err = conn:connect(“192.168.1.222”, 6379)
温馨提示:如果在nginx的上层有用到阿里云的SLB负载均衡的话需要修改一下脚本里的所有…ngx.var.remote_addr
把remote_addr替换成从SLB获取真实IP的字段即可,不然获取到的IP全都是阿里云SLB发过来处理过的IP,全都是一个网段的,根本没有办法起到封禁的效果)

 

cat /usr/local/openresty/nginx/conf/waf/accessip.lua

 

 

2、在需要做访问限制的location里加两段代码即可,这里用刚才的/lua做演示

 

images

 

 

 

 

 

 

 

 

 

 

 

 

 

主要添加
access_by_lua_file /usr/local/openresty/nginx/conf/lua/access.lua;
让没一个请求都去调用这个lua脚本,注意路径和名字不要写错
set $business “lua” 是为了把IP放进redis的时候标明是哪个location的,可以不加
[root@test1 lua]# nginx -s reload #修改完后重启nginx

3、去访问192.168.1.222/lua 并一直按F5刷新

 

发现redis已经在统计访问lua这个网页ip的访问次数
这个key的过期时间是30秒,如果30秒没有重复访问20次这个key就会消失,所以说正常用户一般不会触发这个封禁的脚本
当30秒内访问超过了20次
发现触发脚本了,变成了403

这个脚本的目的很简单:一个IP如果在30秒内其访问次数达到20次则表明该IP访问频率太快了,因此将该IP封禁5分钟。同时由于计数的KEY在Redis中的超时时间设置成了30秒,所以如果两次访问间隔时间大于30秒将会重新开始计数

后续这个脚本可以继续优化,比如第一次封禁300秒,第二次再进去封3天,再进去永久封禁之类的,不过能力有限,还得继续研究,如果上面写的有什么错误,欢

 

Leave a Reply

Your email address will not be published. Required fields are marked *