一、背景
目前国内WAF接入成本过高,考虑自建WAF实现7层防御。这里使用nginx_lua + ModSecurity进行组合防御。其中lua用做防御cc攻击,ModSecurity用来防御其他7层攻击。以下环境搭建使用centos7.9+openresty
cc攻击脚本参考
- https://github.com/loveshell/ngx_lua_waf
- https://github.com/unixhot/waf
ModSecurity防护参考
- https://github.com/SpiderLabs/ModSecurity
- https://github.com/SpiderLabs/ModSecurity-nginx
- https://github.com/SpiderLabs/ModSecurity/wiki/Compilation-recipes-for-v3.x
二、安装ModSecurity
2.1 依赖软件安装
参考依赖软件安装,地址:https://github.com/SpiderLabs/ModSecurity/wiki/Compilation-recipes-for-v3.x
[root@iZj6cae06zxj2lpnpoomzwZ ~]# yum install gcc-c++ flex bison yajl yajl-devel curl-devel curl GeoIP-devel doxygen zlib-devel pcre-devel -y
[root@iZj6cae06zxj2lpnpoomzwZ ~]# yum -y install autoconf automake libtool git
2.2 安装ModSecurity
[root@iZj6cae06zxj2lpnpoomzwZ ~]# git clone https://github.com/SpiderLabs/ModSecurity.git
[root@iZj6cae06zxj2lpnpoomzwZ ~]# cd ModSecurity/
[root@iZj6cae06zxj2lpnpoomzwZ ModSecurity]# git branch #v3/master 分支
[root@iZj6cae06zxj2lpnpoomzwZ ModSecurity]# ./build.sh
[root@iZj6cae06zxj2lpnpoomzwZ ModSecurity]# git submodule init
[root@iZj6cae06zxj2lpnpoomzwZ ModSecurity]# git submodule update
[root@iZj6cae06zxj2lpnpoomzwZ ModSecurity]# ./configure
[root@iZj6cae06zxj2lpnpoomzwZ ModSecurity]# yum install https://archives.fedoraproject.org/pub/archive/fedora/linux/updates/23/x86_64/b/bison-3.0.4-3.fc23.x86_64.rpm
[root@iZj6cae06zxj2lpnpoomzwZ ModSecurity]# make
[root@iZj6cae06zxj2lpnpoomzwZ ModSecurity]# make install
2.3 下载ModSecurity-nginx
[root@iZj6cae06zxj2lpnpoomzwZ tmp]# git clone https://github.com/SpiderLabs/ModSecurity-nginx.git
[root@iZj6cae06zxj2lpnpoomzwZ tmp]# mv ModSecurity-nginx /usr/local/
三、安装OpenResty
[root@iZt4n2w8edhjcih8oyjcl3Z ~]# wget -c http://mirrors.linuxeye.com/oneinstack-full.tar.gz && tar xzf oneinstack-full.tar.gz
[root@iZj6cae06zxj2lpnpoomzwZ ~]# cd oneinstack/include/
[root@iZj6cae06zxj2lpnpoomzwZ include]# vim openresty.sh
添加如下编译参数:
--add-module=/usr/local/ModSecurity-nginx
[root@iZj6cae06zxj2lpnpoomzwZ ~]# ./oneinstack/install.sh --nginx_option 3 --reboot #安装
# 备注:脚本参考https://github.com/oneinstack/oneinstack
四、配置检查
4.1 检测日志是否正常
[root@iZt4n2w8edhjcih8oyjcl3Z ~]# cat /usr/local/openresty/nginx/logs/error.log
2023/04/23 10:59:47 [notice] 11277#0: ModSecurity-nginx v1.0.3 (rules loaded inline/local/remote: 0/0/0)
2023/04/23 10:59:47 [notice] 11280#0: ModSecurity-nginx v1.0.3 (rules loaded inline/local/remote: 0/0/0)
2023/04/23 10:59:59 [notice] 887#0: ModSecurity-nginx v1.0.3 (rules loaded inline/local/remote: 0/0/0)
2023/04/23 10:59:59 [notice] 942#0: ModSecurity-nginx v1.0.3 (rules loaded inline/local/remote: 0/0/0)
2023/04/23 11:00:55 [notice] 1317#0: ModSecurity-nginx v1.0.3 (rules loaded inline/local/remote: 0/0/0)
# 备注:ModSecurity-nginx v1.0.3 表示ModSecurity-nginx已经安装完成
4.2 nginx检测
[root@iZj6cae06zxj2lpnpoomzwZ ~]# nginx -V
nginx version: openresty/1.21.4.1
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC)
built with OpenSSL 1.1.1t 7 Feb 2023
TLS SNI support enabled
configure arguments: --prefix=/usr/local/openresty/nginx ...
--add-module=/usr/local/ModSecurity-nginx
# 备注:add-module=/usr/local/ModSecurity-nginx 表示已经添加了此模块,同时在之后的步骤不会写关于ModSecurity OWASP CRS的集成
4.3ModSecurity配置
…
五、Lua防御cc攻击配置
5.1 下载waf脚本
[root@iZt4n2w8edhjcih8oyjcl3Z ~]# git clone https://gitee.com/xiangys0134/deploy.git
[root@iZt4n2w8edhjcih8oyjcl3Z ~]# cd deploy/nginx-lua/ngx_lua_waf
[root@iZt4n2w8edhjcih8oyjcl3Z ngx_lua_waf]# cp -r waf /usr/local/openresty/nginx/conf/
# 个人仓库已由github迁移至码云
5.2 配置lua防护规则
[root@iZt4n9mhb57oqffa6jxg2yZ conf]# vim nginx.conf
http区块下添加如下内容:
lua_package_path "/usr/local/openresty/nginx/conf/waf/?.lua;;";
lua_shared_dict limit 50m;
init_by_lua_file /usr/local/openresty/nginx/conf/waf/init.lua;
access_by_lua_file /usr/local/openresty/nginx/conf/waf/waf.lua;
# 备注:这里默认所有站点在access_by_lua这块都会进行waf防御,也可以将其写入到对应的server区块中。具体看自己需求
[root@iZt4n2w8edhjcih8oyjcl3Z conf]# nginx -t
[root@iZt4n2w8edhjcih8oyjcl3Z conf]# systemctl restart nginx
5.3 测试cc攻击
[root@iZt4n2w8edhjcih8oyjcl3Z conf]# vim waf/config.lua # 配置符合自己的规则
ipWhitelist={"127.0.0.1"}
ipBlocklist={"1.0.0.1"}
CCDeny="on"
CCrate="100/60"
# 这里我简化了源作者的以下功能,所以只用以上几个核心参数就够了。CCrate="100/60"表示60秒内有超过100个请求则拦截1分钟
ubuntu@VM-12-8-ubuntu:~ab -c 600 -n 600 http://8.222.192.68/ # ab测试
ubuntu@VM-12-8-ubuntu:~ curl -I http://8.222.192.68/ # 客户端测试访问,返回状态码429,拦截成功
HTTP/1.1 429 Too Many Requests
Server: openresty
Date: Sun, 23 Apr 2023 03:16:57 GMT
Content-Type: text/html
Content-Length: 166
Connection: keep-alive
六、写在最后
6.1函数获取客户ip
# 获取客户端ip函数如下:
function string:split(sep)
local splits = {}
if sep == nil then
-- return table with whole str
table.insert(splits, self)
elseif sep == "" then
-- return table with each single character
local len = #self
for i = 1, len do
table.insert(splits, self:sub(i, i))
end
else
--local pattern = "[^" .. sep .. "]+"
local str_result = string.match(self, sep)
if str_result == nil then
table.insert(splits, self)
else
-- normal split use gmatch
local pattern = "[^" .. sep .. "]+"
for str in string.gmatch(self, pattern) do
table.insert(splits, str)
end
end
end
return splits
end
function getClientIp()
IP = ngx.req.get_headers()["X_real_ip"]
if IP == nil then
IP = ngx.req.get_headers()["X_Forwarded_For"]
if not IP == nil then
IP = string.split(IP, ',')[1]
end
end
if IP == nil then
IP = ngx.var.remote_addr
end
if IP == nil then
IP = "unknown"
end
return IP
6.2 其他场景验证
[root@iZt4n2w8edhjcih8oyjcl3Z conf]# vim nginx.conf # 新增配置
location /test1 {
content_by_lua_block {
-- local CLIENT_IP= ngx.req.get_headers(0)["x_forwarded_for"]
local CLIENT_IP= ngx.req.get_headers()["x_forwarded_for"]
--local CLIENT_IP= ngx.req.get_headers()["X_real_ip"]
ngx.say(CLIENT_IP);
}
}
[root@iZt4n2w8edhjcih8oyjcl3Z conf]# nginx -t
[root@iZt4n2w8edhjcih8oyjcl3Z conf]# systemctl restart nginx
# 客户端测试
ubuntu@VM-12-8-ubuntu:~curl -H 'X-Forwarded-For: 1.2.3.4 ' http://8.222.192.68/test1
1.2.3.4
ubuntu@VM-12-8-ubuntu:~ curl -H 'X-Forwarded-For: 1.2.3.4,2.3.3.3 ' http://8.222.192.68/test1
1.2.3.4,2.3.3.3
# 备注:这里获取到x_forwarded_for标头信息时还需要做一下字符串切割,以后再补充
6.3 脚本地址
- https://gitee.com/xiangys0134/ngx_lua_waf/blob/master/waf-redis/init.lua
留言