前言
众所周知,宝塔面板有商用的Nginx防火墙插件(要钱),具有丰富的WAF(Web Application Firewall)功能,但是其防CC能力在面对攻击时形同虚设,使用简单的CC工具就可以轻松实现503 Page。而较老的httpguard、ngx_lua_waf等均已年久失修。偶然间在Github上发现了ngx_waf后折腾了一下发现确实不错。
NGX_WAF简介
方便且高性能的 Nginx 防火墙模块。(以下内容来自原项目介绍)
为什么选择 ngx_waf
功能齐全:「网络应用防火墙」的基本功能都有。
安装方便:大多数情况下你可以直接下载使用预构建的模块,而不是编译代码。
使用方便:配置指令简单易懂,不用看文档都能猜到大概是什么意思。
规则灵活:提供高级规则,将动作(如拦截或放行)和多个条件表达式组合起来。
高性能:经过较为极限的测试,启动本模块后 RPS(每秒请求数) 降低约 4%。测试说明和结果见使用文档。
功能
SQL 注入防护。
XSS 攻击防护。
支持 IPV4 和 IPV6。
CC 防御,超出限制后自动拉黑对应 IP 一段时间。
IP 黑白名单,同时支持类似 192.168.0.0/16 和 fe80::/10,即支持点分十进制和冒号十六进制表示法和网段划分。
POST 黑名单。
URL 黑白名单
查询字符串(Query String)黑名单。
UserAgent 黑名单。
Cookie 黑名单。
Referer 黑白名单。
高级规则,将动作(如拦截或放行)和多个条件表达式组合起来。
相关链接
使用文档:https://docs.addesp.com/ngx_waf/zh-cn/
GitHub:https://github.com/ADD-SP/ngx_waf
总结
一个用C构建的高效率Nginx防火墙,开发者积极维护(在写稿的时候就更新了3个版本导致不得不反复修改),并且支持开启5秒盾,实测抗CC性能优秀!
安装方法
以下内容源于官方文档,仅供参考!
环境
CentOS 7
Nginx 1.21.0
宝塔 7.6.0
ngx_waf v7.0.0 Current
如果您的环境相同,以下安装指令可以照抄,反之请自行检查相关指令。
安装过程
首先创建临时的工作目录,并将项目拷贝到本地。
mkdir /root/nginx #临时工作目录,这个在后面会用到
cd /root/nginx
git clone https://github.com/ADD-SP/ngx_waf.git #获取最新版本的ngx_waf,也可以直接去Release找以往的版本
cd ngx_waf
git clone https://github.com/libinjection/libinjection.git inc/libinjection
nginx 提供两种安装模块的方式,即「静态链接」和「动态加载」,通过两种方式安装的模块也分别称为「静态模块」和「动态模块」。
你可以通过运行脚本 assets/guide.sh 来选择使用静态模块还是动态模块。
sh assets/guide.sh
# It is recommended that you use dynamic modules.
# 如果输出上面这行则建议使用动态模块。
# It is recommended that you use static modules.
# 如果输出上面这行则建议使用静态模块。
在宝塔环境下得到的推荐是静态模块,实际在折腾过文章介绍的动态模块后均会出现奇怪的错误,于是在后文介绍的是静态模块安装。
到这一步我们需要开始进行编译,这里可能会涉及各种依赖问题如gcc等,由于不同环境的依赖问题不一样,这里就不再赘述,请自行通过搜索引擎解决。
在搞定依赖问题后需要获取当前nginx的configure 脚本的参数,在宝塔环境下输入以下指令即可获得。
/www/server/nginx/sbin/nginx -V
得到以下内容,这里将configure arguments:
后面的内容记录下来,并在结尾加上--add-module=/usr/local/src/ngx_waf
即可得到编译参数。如果您使用的编译器是 GCC,请在 --with-cc-opt
中追加 -fstack-protector-strong
, 例如 --with-cc-opt='-Werror -g' ---> --with-cc-opt='-Werror -g -fstack-protector-strong'
。
nginx version: nginx/1.21.0
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC)
built with OpenSSL 1.1.1k 25 Mar 2021
TLS SNI support enabled
configure arguments: --user=www --group=www --prefix=/www/server/nginx --add-module=/www/server/nginx/src/ngx_devel_kit --add-module=/www/server/nginx/src/lua_nginx_module --add-module=/www/server/nginx/src/ngx_cache_purge --add-module=/www/server/nginx/src/nginx-sticky-module --with-openssl=/www/server/nginx/src/openssl --with-pcre=pcre-8.43 --with-http_v2_module --with-stream --with-stream_ssl_module --with-stream_ssl_preread_module --with-http_stub_status_module --with-http_ssl_module --with-http_image_filter_module --with-http_gzip_static_module --with-http_gunzip_module --with-ipv6 --with-http_sub_module --with-http_flv_module --with-http_addition_module --with-http_realip_module --with-http_mp4_module --with-ld-opt=-Wl,-E --with-cc-opt=-Wno-error --with-ld-opt=-ljemalloc --with-http_dav_module --add-module=/www/server/nginx/src/nginx-dav-ext-module --with-cc-opt=-std=gnu99
接下来开始编译ngx_waf模块与nginx,以下代码会用到上述处理好的编译参数。
cd /root/nginx/ngx_waf
make
cd /www/server/nginx/src
./configure --user=www --group=www --prefix=/www/server/nginx --add-module=/www/server/nginx/src/ngx_devel_kit --add-module=/www/server/nginx/src/lua_nginx_module --add-module=/www/server/nginx/src/ngx_cache_purge --add-module=/www/server/nginx/src/nginx-sticky-module --with-openssl=/www/server/nginx/src/openssl --with-pcre=pcre-8.43 --with-http_v2_module --with-stream --with-stream_ssl_module --with-stream_ssl_preread_module --with-http_stub_status_module --with-http_ssl_module --with-http_image_filter_module --with-http_gzip_static_module --with-http_gunzip_module --with-ipv6 --with-http_sub_module --with-http_flv_module --with-http_addition_module --with-http_realip_module --with-http_mp4_module --with-ld-opt=-Wl,-E --with-cc-opt=-Wno-error --with-ld-opt=-ljemalloc --with-http_dav_module --add-module=/www/server/nginx/src/nginx-dav-ext-module --add-module=/root/nginx/ngx_waf --with-cc-opt='-std=gnu99'
make
mv ../sbin/nginx ../sbin/nginx.bak
cp ./objs/nginx ../sbin/nginx
chmod +x /www/server/nginx/sbin/nginx
到这里就已经替换原有的Nginx程序,接下来在宝塔中启动Nginx即可!
若您出现如下报错:
nginx: the configuration file /www/server/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /www/server/nginx/conf/nginx.conf test failed
则需要先卸载宝塔的Nginx防火墙再重新安装!
到此为止,安装与编译结束。
配置
在安装完成后我们可以将配置文件加入单个站点的配置文件中以实现未不同网站定制不同的规则,配置填写位置如图:
以下介绍我的配置,内容并不完善,各参数与各模块具体功能请详见参考文档!
waf on; # 是否启用模块
waf_rule_path /root/nginx/ngx_waf/assets/rules/; # 模块规则
waf_mode DYNAMIC; # 启用动态网站模式
waf_cache capacity=100; # 设置缓存规则检查结果相关的参数,过小会导致频繁地淘汰缓存,增加内存碎片,降低性能
waf_under_attack on file=/www/wwwroot/defence.html; # 对所有访问的用户开启5秒盾,file需要填写单个html的绝对路径!请仅在网站遭受大量攻击的时候打开!其中该html的作用为5秒之后刷新页面!
waf_cc_deny rate=300r/m duration=10m size=20m; #每分钟请求大于300次则封禁10分钟,最多缓存20M大小的请求记录
如果使用CDN或负载均衡等反向代理程序,为获取真实的客户IP地址,需要用到http_realip_module,宝塔的Nginx已经默认编译该模块。此时我们需要在配置文件中加入:
set_real_ip_from 0.0.0.0/0; #CDN节点的IP段,此项可多次申明,请根据实际情况填写,照抄危险!
real_ip_header X-Forwarded-For;
以上提到了用于5秒盾跳转的HTML页面,以下是我自己的一个版本,仅供参考。
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>正在检查您的浏览器...</title>
<link href="https://oss.mezhiyu.com/css/css?family=Kanit:200" rel="stylesheet">
<style type="text/css">
*{-webkit-box-sizing:border-box;box-sizing:border-box}body{padding:0;margin:0}#defence{position:relative;height:100vh}#defence .defence{position:absolute;left:50%;top:50%;-webkit-transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%);transform:translate(-50%,-50%)}.defence{max-width:767px;width:100%;line-height:1.4;text-align:center;padding:15px}.defence .defence-404{position:relative;height:220px}.defence .defence-404 h1{font-family:Kanit,sans-serif;position:absolute;left:50%;top:50%;-webkit-transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%);transform:translate(-50%,-50%);font-size:186px;font-weight:200;margin:0;background:linear-gradient(130deg,#ffa34f,#ff6f68);color:transparent;-webkit-background-clip:text;background-clip:text;text-transform:uppercase}.defence h2{font-family:Kanit,sans-serif;font-size:33px;font-weight:200;text-transform:uppercase;margin-top:0;margin-bottom:25px;letter-spacing:3px}.defence p{font-family:Kanit,sans-serif;font-size:16px;font-weight:200;margin-top:0;margin-bottom:25px}.defence a{font-family:Kanit,sans-serif;color:#ff6f68;font-weight:200;text-decoration:none;border-bottom:1px dashed #ff6f68;border-radius:2px}.defence-social>a{display:inline-block;height:40px;line-height:40px;width:40px;font-size:14px;color:#ff6f68;border:1px solid #efefef;border-radius:50%;margin:3px;-webkit-transition:.2s all;transition:.2s all}.defence-social>a:hover{color:#fff;background-color:#ff6f68;border-color:#ff6f68}@media only screen and (max-width:480px){.defence .defence-404{position:relative;height:168px}.defence .defence-404 h1{font-size:142px}.defence h2{font-size:22px}}
</style>
<script type="text/javascript">
setTimeout("window.location.reload();","6000");
</script>
</head>
<body>
<div id="defence">
<div class="defence">
<div class="defence-404">
<h1>OOPS!</h1>
</div>
<h2>站点正在被攻击!您的请求正在接受检查...</h2>
<p>请给我们一些时间,您马上就会回到站点,这会很快~</p>
</div>
</div>
</body>
</html>
将以上内容保存到/www/wwwroot/defence.html即可。
测试
访问 /www.bak,如果返回 403 状态码则表示模块成功启动。
结语
至此ngx_waf模块安装结束,在配置好一定的防御策略之后可以获得不错的防御能力。其实跟云锁的部署差不多。