Zhongkui-WAF
钟馗是中国传统文化中的一个神话人物,被誉为“捉鬼大师”,专门驱逐邪恶之物。Zhongkui-WAF
的命名灵感来源于这一神话人物,寓意着该软件能够像钟馗一样,有效地保护Web应用免受各种恶意攻击和威胁。
Zhongkui-WAF
基于lua-nginx-module
,可以多维度检查和拦截恶意网络请求,具有简单易用、高性能、轻量级的特点。它的配置简单,你可以根据实际情况设置不同的安全规则和策略。
Zhongkui-WAF项目地址:GitHub地址 Gitee地址
主要特性
- 多种工作模式,可随时切换
- 关闭模式:放行所有网络请求
- 保护模式(protection):拦截攻击请求并记录攻击日志
- 监控模式(monitor):记录攻击日志但不拦截攻击请求
- 支持规则自动排序,开启后按规则命中次数降序排序,可提高拦截效率
- 支持ACL自定义规则,灵活配置拦截规则
- IP黑名单、白名单,支持网段配置,“127.0.0.1/24"或"127.0.0.1/255.255.255.0”
- HTTP Method白名单
- URL黑名单、白名单
- URL恶意参数拦截
- 恶意Header拦截
- 请求体检查
- 上传文件类型黑名单,防止webshell上传
- 恶意Cookie拦截
- CC攻击拦截,浏览器验证失败后可以自动限时或永久拉黑IP地址
- Sql注入、XSS、SSRF等攻击拦截
- 可设置仅允许指定国家的IP访问
- 敏感数据(身份证号码、手机号码、银行卡号、密码)脱敏及关键词过滤
- 支持Redis,开启后IP请求频率、IP黑名单等数据将从Redis中读写
- 攻击日志记录,包含IP地址、IP所属地区、攻击时间、防御动作、拦截规则等,支持JSON格式日志
- 流量统计可视化
安装
强烈推荐使用OpenResty
。
因为使用的WAF模块是基于lua
的,如果你使用Nginx
,则需要安装LuaJIT
和lua-nginx-module
模块,让Nginx
支持lua
。并下载lua-resty-redis库到path-to-zhongkui-waf/lib/resty
目录。
Nginx安装lua模块
如果你使用OpenResty,可以跳过此节。
安装lua
的库:
yum install -y lua lua-devel
下载lua即时编译器LuaJIT:
wget -O /usr/local/src/LuaJIT-2.1-20220411.tar.gz https://github.com/openresty/luajit2/archive/v2.1-20220411.tar.gz
解压:
cd /usr/local/src
tar -zxvf LuaJIT-2.1-20220411.tar.gz
安装LuaJIT:
cd /usr/local/src/LuaJIT-2.1-20220411
make && make install PREFIX=/usr/local/luajit2-2.1
编辑/etc/profile文件,添加LuaJIT
环境变量:
export LUAJIT_LIB=/usr/local/luajit2-2.1/lib
export LUAJIT_INC=/usr/local/luajit2-2.1/include/luajit-2.1
加载lua库到ld.so.conf文件:
echo "/usr/local/LuaJIT/lib" >> /etc/ld.so.conf
执行动态链接库管理命令,让动态链接库为系统所共享:
ldconfig
下载Nginx模块,ngx_devel_kit
和lua-nginx-module
:
wget -O /usr/local/src/ngx_devel_kit-0.3.1.tar.gz https://github.com/simplresty/ngx_devel_kit/archive/v0.3.1.tar.gz
wget -O /usr/local/src/lua-nginx-module-0.10.14.tar.gz https://github.com/openresty/lua-nginx-module/archive/v0.10.14.tar.gz
分别解压两个模块到/usr/local/nginx-modules/
目录:
tar -zxvf ngx_devel_kit-0.3.1.tar.gz -C /usr/local/nginx-modules/
tar -zxvf lua-nginx-module-0.10.14.tar.gz -C /usr/local/nginx-modules/
安装Nginx时,通过configure
命令添加上面这两个模块:
./configure --prefix=/usr/local/nginx \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_realip_module \
--with-http_sub_module \
--with-http_stub_status_module \
--with-http_auth_request_module \
--with-http_secure_link_module \
--with-stream \
--with-stream_ssl_module \
--with-stream_realip_module --without-http_fastcgi_module \
--without-select_module \
--without-poll_module \
--add-module=/usr/local/nginx-modules/ngx_devel_kit-0.3.1 \
--add-module=/usr/local/nginx-modules/lua-nginx-module-0.10.14 \
--with-ld-opt=-Wl,-rpath,/usr/local/luajit2-2.1/lib
waf
假设OpenResty
安装路径为:/usr/local/openresty
,下载zhongkui-waf
文件并放置在/usr/local/openresty/zhongkui-waf
目录。
修改nginx.conf
,在http
模块下添加zhongkui-waf
相关配置:
lua_shared_dict dict_cclimit 10m;
lua_shared_dict dict_accesstoken 10m;
lua_shared_dict dict_blackip 10m;
lua_shared_dict dict_locks 100k;
lua_shared_dict dict_config 5m;
lua_shared_dict dict_config_rules_hits 5m;
lua_shared_dict dict_req_count 5m;
lua_package_path "/usr/local/openresty/zhongkui-waf/?.lua;/usr/local/openresty/zhongkui-waf/lib/?.lua;;";
init_by_lua_file /usr/local/openresty/zhongkui-waf/init.lua;
init_worker_by_lua_file /usr/local/openresty/zhongkui-waf/init_worker.lua;
access_by_lua_file /usr/local/openresty/zhongkui-waf/waf.lua;
body_filter_by_lua_file /usr/local/openresty/zhongkui-waf/body_filter.lua;
header_filter_by_lua_file /usr/local/openresty/zhongkui-waf/header_filter.lua;
log_by_lua_file /usr/local/openresty/zhongkui-waf/dashboard/count_traffic.lua;
libmaxminddb库
IP地理位置识别需要下载MaxMind的IP地址数据文件及安装该IP数据文件的读取库。
- 从MaxMind官网下载GeoLite2 City数据文件,后续可使用官方工具对该数据文件自动更新。
- 安装
libmaxminddb
库
wget -P /usr/local/src https://github.com/maxmind/libmaxminddb/releases/download/1.7.1/libmaxminddb-1.7.1.tar.gz
tar -zxvf libmaxminddb-1.7.1.tar.gz
cd libmaxminddb-1.7.1
./configure
make && make install
echo /usr/local/lib >> /etc/ld.so.conf.d/local.conf
ldconfig
Windows系统用户要自行编译,生成libmaxminddb.dll
文件,具体参考maxmind/libmaxminddb
官方文档using-cmake。
安装完成后重启OpenResty
,使用测试命令:
curl http://localhost/?t=../../etc/passwd
看到waf返回的禁止访问信息则说明安装成功。
配置
Zhongkui-WAF
的基本配置在config.lua
文件中,你可以对它进行修改。
ip黑名单列表可以配置在config.lua
文件中,也可以配置在path-to-zhongkui-waf/rules/ipBlackList
文件中。
不管是基本配置还是规则文件,修改完后都要执行nginx -s reload
命令来重新载入配置。
path-to-zhongkui-waf/rules
目录下是一系列规则文件,文件内容都是json
格式。你可以新增自己的规则,也可以对每条规则进行单独设置,如打开、关闭或者修改其拦截动作等。
拦截动作有如下几种:
-
allow
:允许当前请求并记录日志。 -
deny
:拒绝当前请求,返回HTTP状态码403并记录日志。 -
redirect
:拒绝当前请求,返回拦截页面并记录日志。 -
coding
:对匹配到的内容进行过滤,替换为*
。 -
redirect_js
:浏览器验证,JavaScript重定向。 -
redirect_302
:浏览器验证,302重定向。
一些配置项是通用的:
-
state
:是该条规则的开关状态,on
是开启,off
是关闭。 -
description
:是对该规则的描述,起到方便管理的作用。
配置项redirect
是Zhongkui-WAF
的私钥,用于浏览器验证请求签名等,应妥善保管,安装后建议修改下,格式为任意字符组合,建议长度长一点。
配置项logPath
是WAF
日志文件输出目录,需要注意的是,一定要确保OpenResty
对日志目录有写入权限,否则WAF
会无法产生日志文件。你可以使用类似如下命令来授权:
chown ./hack nobody 或者 chmod 744 ./hack
CC攻击防御
cc攻击的配置文件是path-to-zhongkui-waf/rules/cc.json
,可按单URL
和单IP
进行统计,超过阈值时直接拒绝请求或对浏览器进行验证,验证失败后可自动屏蔽IP地址。
配置项说明:
-
countType
:统计类型,值为"url"或"ip"。 -
duration
:统计时长,单位是秒。 -
threshold
:阈值,单位是次。 -
action
:cc攻击处置动作,redirect_js
、redirect_302
仅适用于网页或H5,APP或API等环境,应设置为:deny
。 -
autoIpBlock
:在浏览器验证失败后自动屏蔽IP,on
是开启,off
是关闭。拉黑日志保存在./logPath/ipBlock.log
文件中。 -
ipBlockTimeout
:ip禁止访问时间,单位是秒,如果设置为0
则永久禁止并保存在./rules/ipBlackList
文件中。
Bot管理
Bot管理的配置文件是path-to-zhongkui-waf/rules/user-agent.json
。可以配置对bot采取阻止、放行、浏览器验证或IP屏蔽等处置动作。
bot黑名单
zhongkui-waf
内置了一些自动扫描工具及恶意爬虫等的User-Agent
,默认会阻止User-Agent
在黑名单中的请求。
bot白名单
开启后,一些常见的搜索引擎爬虫将被放行,目前包含Google、百度、搜狗、Bing、360、Yandex等。
bot陷阱
bot陷阱的配置在config.lua
文件中,开启bot陷阱后,将会在上游服务器返回的HTML页面中添加配置的陷阱URL,这个URL隐藏在页面中,对普通正常用户不可见,访问此URL的请求被视为bot。
建议bot陷阱结合robots协议
使用,将陷阱URI配置为禁止所有bot访问,不听话的bot将访问陷阱URL,从而被识别,而那些遵循robots协议
的友好bot将不会被陷阱捕获。
你可以在robots.txt中这样配置:
User-agent: *
Disallow: /zhongkuiwaf/honey/trap
ACL自定义规则
自定义规则的配置文件是path-to-zhongkui-waf/rules/acl.json
,你可以按实际需要灵活配置规则组合。
配置项说明:
-
rule
:规则名称。 conditions
:匹配条件,可以是多个条件的组合,每个条件之间为”且“的关系。
-
field
:匹配字段,可以是URL
、Cookie
、Header
、Referer
、User-Agent
。 -
pattern
:匹配内容,对字段进行匹配的正则表达式,当设置为""时,则表示匹配对应field
不存在的请求。 -
name
:当field为Cookie
或Header
时,可以匹配具体的Cookie Name或Header Name。
-
action
:匹配到规则后的处置动作,redirect_js
、redirect_302
仅适用于网页或H5,APP或API等环境,应设置为:deny
。 -
autoIpBlock
:匹配到规则后自动屏蔽IP,on
是开启,off
是关闭。拉黑日志保存在./logPath/ipBlock.log
文件中。 -
ipBlockTimeout
:ip禁止访问时间,单位是秒,如果设置为0
则永久禁止并保存在./rules/ipBlackList
文件中。
下面这个例子,可以拦截URL为/test/12345.html
且没有Cookie
的请求:
{
"rules": [
{
"state": "on",
"rule": "no Cookie",
"conditions": [
{
"field": "URL",
"pattern": "/test/\\d+\\.html"
},
{
"field": "Cookie",
"pattern": ""
}
],
"action": "deny",
"autoIpBlock": "off",
"ipBlockTimeout": 60,
"description": "拦截不带Cookie的请求"
}
]
}
拦截Cookie name为JSESSIONID
,值为aaaROKLSA3MYZ9rvxgLHy
的请求:
{
"rules": [
{
"state": "on",
"rule": "Cookie JSESSIONID",
"conditions": [
{
"field": "Cookie",
"name": "JSESSIONID",
"pattern": "aaaROKLSA3MYZ9rvxgLHy"
}
],
"action": "deny",
"autoIpBlock": "off",
"ipBlockTimeout": 60,
"description": "拦截JSESSIONID为aaaROKLSA3MYZ9rvxgLHy的请求"
}
]
}
敏感数据过滤
开启敏感信息过滤后,Zhongkui-WAF
将对响应数据进行过滤。
Zhongkui-WAF
内置了对响应内容中的身份证号码、手机号码、银行卡号、密码信息进行脱敏处理。需要注意的是,内置的敏感信息脱敏功能目前仅支持处理中华人民共和国境内使用的数据格式(如身份证号、电话号码、银行卡号),暂不支持处理中国境外的身份证号、电话号码、银行卡号等数据格式。但你可以使用正则表达式配置不同的规则,以过滤请求响应内容中任何你想要过滤掉的数据。
敏感信息过滤配置在在sensitive.json
文件中。
例如:
{
"rules": [{
"state": "on",
"action": "coding",
"codingRange": "4,-5",
"rule": "(?:(?:\\+|00)86)?1(?:(?:3[\\d])|(?:4[5-79])|(?:5[0-35-9])|(?:6[5-7])|(?:7[0-8])|(?:8[\\d])|(?:9[189]))\\d{8}",
"description": "mobile number"
},
{
"state": "on",
"action": "coding",
"codingRange": "$1",
"rule": "(?:password|passwd)\"\\s*[:=]\\s*\"(\\S+)\"",
"description": "password"
}
],
"words": ["fuck", "bitch", "balabala"]
}
action
是匹配到该条规则后的响应动作,目前敏感信息过滤只有coding
这一种有效,即对敏感信息脱敏处理。
rule
是要处理的信息的匹配规则,通常是一个正则表达式。
codingRange
是匹配到的字符串中要处理的子字符串范围,有两种形式:
- 直接标明要处理的子字符串的起始位置:
- 如字符串
15800000000
的codingRange
为“4,7”
,则会将对从第四个位置开始到第七个位置之间的所有字符进行处理,结果为158****0000
。 - 起始位置也可以是一个负数,如字符串
15800000000
的codingRange
为“4,-5”
,则会将对从第四个位置开始到倒数第五个位置之间的所有字符进行处理,结果为158****0000
。
- 使用
$
字面量加数字,比如:$0
指的是由该模式匹配的整个子串,而$1
指第一个带括号的捕获子串。
words
是一个数组,可以用来配置一些需要过滤掉的关键词。
流量统计可视化
Zhongkui-WAF
内置了简单的流量统计可视化功能,目前仅支持查看当天请求流量、攻击请求流量及攻击类别统计。
需要将dashboard
设置为"on",然后在Nginx
配置文件中配置访问地址:
location /zhongkui/dashboard {
auth_basic on;
auth_basic_user_file /usr/local/openresty/nginx/conf/passwd;
content_by_lua_file /usr/local/openresty/zhongkui-waf/dashboard/dashboard.lua;
}
这个url地址可以是任意地址,建议安装后修改,并且不要太简单,如/admin
之类,否则很容易被猜测到。
建议开启auth_basic
认证,可以使用openssl生成密码:
openssl passwd -apr1
auth_basic_user_file
文件内容格式为:
用户名:密码
浏览器访问/zhongkui/dashboard
,效果图如下: