一、背景

目前国内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
最后修改日期: 2024年5月6日

作者

留言

撰写回覆或留言

发布留言必须填写的电子邮件地址不会公开。