百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

使用 Nginx 三方扩展 ngx_waf 快速实现一个高性能的 Web 应用防火墙

off999 2025-02-21 14:49 24 浏览 0 评论

ngx_waf:方便且高性能的 Nginx 防火墙模块

缓存策略为 LRUIP 检查和 CC 防御花费常数时间,其它的检查花费 O(nm) 的时间,其中 n 是相关规则的条数,m 为执行正则匹配的时间复杂度,但是每次检查过后会自动缓存本次检查的结果,下次检查相同的目标时就可以使用缓存而不是检查全部的规则。不会缓存 POST 请求体的检查结果。

Docker中文社区旨在为大家提供 Docker、Kubernetes 相关工具及前沿资讯信息,方便大家了解学习 Docker、Kubernetes 相关容器技术。官网:dockerworld.cn

?

1工具特点

介绍了该工具的主要特点以及核心功能!

Nginx 的第三方扩展工具,可以防御 CC 攻击(超出限制后自动拉黑对应 IP 一段时间或者使用验证码做人机识别),可以支持多种黑白名单(IP/POST/URL/UA等等),还可以提供防护 SQL 注入和 XSS 工具。

  • 使用简单
    • 配置文件和规则文件书写简单,可读性强
  • 基础防护
    • IPIP 网段的黑白名单、URI 黑白名单和请求体黑名单等
  • 高性能
    • 使用高效的 IP 检查算法和缓存机制,支持 IPV4IPV6
  • 高级防护
    • 兼容 ModSecurity 的规则,你可以使用 OWASP 的核心规则库
  • 友好爬虫验证
    • 支持验证 GoogleBingBaiduYandex 的爬虫并自动放行,避免错误拦截,主要是基于 User-AgentIP 的识别规则
  • 验证码
    • 支持三种验证码:hCaptchareCAPTCHAv2reCAPTCHAv3

2模块安装

第三方模块我们应该怎么安装呢?

Nginx 提供两种安装模块的方式,即「静态链接」和「动态加载」,通过两种方式安装的模块也分别称为「静态模块」和「动态模块」,可以通过运行脚本 assets/guide.sh 来选择使用静态模块还是动态模块。

# 执行如下命令
$ sh assets/guide.sh

# 如果输出下面这行,则建议使用动态模块
# It is recommended that you use dynamic modules.

# 如果输出下面这行,则建议使用静态模块
# It is recommended that you use static modules.
  • [1] 静态模块

编译安装一个新的模块需要知道当前的 Nginxconfigure 脚本的参数,您可以通过运行 nginx -V 来获取,务必记住 configure arguments: 后面的内容。安装静态模块需要重新编译整个 Nginx,花费的时间相对于安装动态模块比较长。如果不想在替换二进制文件时,关闭 Nginx 服务的话,可以参考官方文档的热部署方案。

# 下载对应的Nginx版本
# http://nginx.org/en/download.html
$ cd /usr/local/src
$ wget https://nginx.org/download/nginx-1.20.1.tar.gz
$ tar -zxf nginx-1.20.1.tar.gz

# 使用稳定版的源码
$ cd /usr/local/src
$ git clone -b lts https://github.com/ADD-SP/ngx_waf.git

# 运行配置脚本
$ cd /usr/local/src/nginx-1.20.1
$ ./configure ARG --add-module=/usr/local/src/ngx_waf
$ sed -i 's/^\(CFLAGS.*\)/\1 \
    -fstack-protector-strong -Wno-sign-compare/' \
    objs/Makefile

# 编译(非并行/并行)
$ make
$ make -j$(nproc)

# 替换Nginx二进制文件(假设已经安装过)
$ cp objs/nginx /usr/local/nginx/sbin/nginx
  • [2] 动态模块 - 下载预构建的模块

通过执行脚本 assets/download.sh 来下载动态模块。

# 用于nginx-1.20.1的LTS版的模块
$ sh assets/download.sh 1.20.1 lts

# 用于nginx-1.20.1的最新版的模块
$ sh assets/download.sh 1.20.1 current

# 执行成功后会有如下输出
checking for command ... yes
checking for libc implementation ... yes
 + GNU C libary
Pulling remote image addsp/ngx_waf-prebuild:ngx-1.20.1-module-beta-glibc
......
Download complete!

如果看到 Download complete! 的话,则说明下载成功,模块会被保存在当前目录下。你可以将其拷贝到一个目录下,然后在 nginx.conf 的顶部添加一行。然后关闭 Nginx 服务并运行 nginx -t。如果没有出错则说明模块被正常加载,反之则说明您的 Nginx 不支持预构建的模块,请编译安装模块。

load_module "/path/to/ngx_http_waf_module.so";


  • [3] 动态模块 - 编译动态模块

编译安装动态模块并不需要重新编译整个 Nginx,只需要重新编译所有的模块,所以速度相对静态模块快一些,这也是本文档推荐的方式。

# 下载对应的Nginx版本
# http://nginx.org/en/download.html
$ cd /usr/local/src
$ wget https://nginx.org/download/nginx-1.20.1.tar.gz
$ tar -zxf nginx-1.20.1.tar.gz

# 使用稳定版的源码
$ cd /usr/local/src
$ git clone -b lts https://github.com/ADD-SP/ngx_waf.git

# 运行配置脚本
$ cd /usr/local/src/nginx-1.20.1
$ ./configure --add-dynamic-module=/usr/local/src/ngx_waf --with-compat
$ sed -i 's/^\(CFLAGS.*\)/\1 \
    -fstack-protector-strong -Wno-sign-compare/' \
    objs/Makefile

# 开始编译动态模块
$ make modules

# 将动态模块拷贝到模块目录(关闭服务)
$ cp objs/*.so /usr/local/nginx/modules

最后,在 Nginx 的配置文件顶部添加一行,表示加载这个编译好的模块。

load_module "/usr/local/nginx/modules/ngx_http_waf_module.so";

3模块使用

第三方模块我们应该怎么使用呢?更多参数参考 配置语法

现在就可以在 nginx.conf 内的一个 server 块中添加配置来开启 ngx_waf 模块来配置服务的防火墙了,下面是一个例子。

  • [1] LTS 版本
http {
    ...
    server {
        ...
        # on/off 表示启用和关闭
        waf on;

        # 规则文件所在目录的绝对路径,必须以/结尾
        waf_rule_path /usr/local/src/ngx_waf/assets/rules/;

        # 防火墙工作模式,STD表示标准模式
        waf_mode STD;

        # CC防御参数
        # 1000表示每分钟请求次数上限,超出上限后封禁对应ip地址60分钟
        waf_cc_deny rate=1000r/m duration=60m;

        # 最多缓存50个检测目标的检测结果
        # 对除了IP黑白名单检测、CC防护和POST检测以外的所有检测生效
        waf_cache capacity=50;
        ...
    }
    ...
}
  • [2] Current 版本
http {
    # 声明一块共享内存
    waf_zone name=waf size=20m;
    ...
    server {
        ...
        # on/off 表示启用和关闭
        waf on;

        # 规则文件所在目录的绝对路径,必须以/结尾
        waf_rule_path /usr/local/src/ngx_waf/assets/rules/;

        # 防火墙工作模式,STD表示标准模式
        waf_mode STD;

        # CC防御参数
        # 1000表示每分钟请求次数上限,超出上限后封禁对应ip地址60分钟
        waf_cc_deny on rate=1000r/m duration=60m zone=waf:cc;

        # 对除了IP黑白名单检测、CC防护和POST检测以外的所有检测生效
        waf_cache on capacity=50;
        ...
    }
    ...
}

4常用设置

列出一些 常用的设置,拿来直接就可以使用!

因为模块的配置比较复杂,为了降低使用难度,在这里列出了一些常见用法。

  • [1] 针对路径或文件限流

有时你可能想要限制不同的路径或文件的请求速率,比如静态资源和动态资源使用不同的速率限制。

# LTS

# 将静态资源的请求速率限制到10,000次/分钟
location /static/ {
    waf_cc_deny rate=10000r/m duration=1h;
}

# 将动态资源的请求速率限制到2,000次/分钟
location /dynamic/ {
    waf_cc_deny rate=2000r/m duration=1h;
}
# Current

http {
    waf_zone name=waf size=20m;
    server {
        # 将静态资源的请求速率限制到10,000次/分钟
        location /static/ {
            waf_cc_deny rate=10000r/m duration=1h zone=waf:cc_static;
        }

        # 将动态资源的请求速率限制到2,000次/分钟
        location /dynamic/ {
            waf_cc_deny rate=2000r/m duration=1h zone=waf:cc_dynamic;
        }
    }
}
  • [2] 开启验证码
    • hCaptcha
    • reCAPTCHAv2
    • reCAPTCHAv3

当你的站点受到 CC 攻击时开启验证码是不错的选择,因为验证码可以帮助你进行人机识别。本模块目前支持三种验证码,你应该选择一个并从其网站上申请到 SitekeySecret。配置完成之后,重启 nginx 服务。

# 整个站点开启验证码
server {
    waf_captcha on prov=hCaptcha secret=your_secret sitekey=your_sitekey;
}
# 为某个路径开启验证码
location {
    waf_captcha on prov=hCaptcha secret=your_secret sitekey=your_sitekey;
}
# 当访问频率过高时开启验证码
http {
    waf_zone name=waf size=20m;
    server {
        waf_cc_deny on rate=1000r/m duration=1h zone=waf:cc;
        waf_captcha off prov=hCaptcha secret=your_secret sitekey=your_sitekey;
        waf_action cc_deny=CAPTCHA zone=waf:action;
    }
}
  • [3] 拦截请求时启用验证码

如今,许多攻击者都会使用自动工具攻击服务器,这些自动工具会尝试每一个漏洞,有的会被安全措施所拦截,有的则可以躲避检测。如果攻击者觉得你的价值比较高,可能会手动攻击你的服务。我们并不能完美地防御这些攻击,但却能很简单地提高攻击的成本。

当一个请求被拦截时,ngx_waf 会对该 IP 启用验证码,此时该 IP 想要继续访问就必须完成验证码。这基本可以废掉多数的自动攻击工具,因为这些工具会尝试每一个漏洞,而我们总能识别一些明显的攻击请求并启用验证码,而自动工具时难以通过验证的。对于手动攻击者,这也能提高他们的时间成本。

http {
    waf_zone name=waf size=20m;

    server {
        waf_captcha off prov=xxx sitekey=xxx secret=xxx;
        waf_action blacklist=CAPTCHA zone=waf:action;
    }
}


  • [4] 被攻击时降低带宽占用

当你受到 CC 攻击时,攻击者的 IP 已经被 CC 防护拉黑,但是你的上下行带宽依然很高, 这是因为 CC 防护会返回一个 503 状态码,因此占用了你的带宽,你可以使用下面的配置来降低带宽占用。

444 状态码是 nginx定义的一个非标准的 HTTP 状态码,其作用就是直接关闭连接,不再发送任何数据。如果你使用了 444 状态码,那么在用户看来你的网站就像是不存在一样。这是因为网站出错一般都会有 HTTP 状态码用来提示错误, 如果访问一个网站连错误提示都没有,那么大概率是这个网站不存在。

# LTS
waf_http_status cc_deny=444;
# Current
waf_action cc_deny=444;
  • [5] 抵御分布式 CC 攻击

CC 攻击(HTTP 洪水)是指发送大量的 HTTP 请求来耗尽服务器的资源。如果攻击者使用的 IP 较少则防御较为简单,因为只需要限制 IP 的请求频率,但是如果攻击者使用大量的 IP 进行攻击,仅仅限制 IP 的请求频率是无济于事的。这种使用大量 IP 进行 CC 攻击的方式称为分布式 CC 攻击或分布式 HTTP 洪水。

本模块提供了一些缓解方式,第一种开启验证码来缓解,第二种使用降低带宽占用,第三种使用五秒盾来缓解。你可能听说过 Cloudflare 的五秒盾,本模块的五秒盾和 Cloudflare 的完全不同。它的功能是检测客户端是否能够正确地支持 Cookie,比如发送 Cookie 和正确地处理 Set-Cookie 响应头。你可以从本项目的 assets/ 目录下找到 under-attack.html 并将其拷贝到某个路径下,然后通过修改 nginx 的配置文件来开启五秒盾。

# LTS

# 为整个网站开启五秒盾
server {
    waf_under_attack on file=/path/to/under_attack.html;
}

# 为某个路径开启五秒盾
location /path {
    waf_under_attack on file=/path/to/under_attack.html;
}
# Current

# 为整个网站开启五秒盾
server {
    waf_under_attack on;
}

# 为某个路径开启五秒盾
location /path {
    waf_under_attack on;
}

5效果测试

如需更多帮助,可以参考 如何测试!

当我们部署和配置服务完成之后,需要测试下防火墙是否正常起作用了,可以通过如下方式进行简单的测试来判断规则是否正常运行。

# 测试时的配置
master_process on;
worker_processes  1;

http {
    server {
        listen 80;
        server_name  localhost;

        access_log off;

        waf on;
        waf_mode DYNAMIC !CC !POST;
        waf_rule_path /usr/local/src/ngx_waf/rules/;
        waf_cache capacity=6000 interval=1h percent=50;

        location / {
            default_type text/html;
            return 200 'hello';
        }
    }
}
  • [1] 简易测试
    • 运行下列命令,如果输出 403 则表示模块正常工作
$ curl -I -o /dev/null --user-agent bench \
    -s -w "%{http_code}\\n" https://example.com
  • [2] 自动测试
    • 项目附带了许多测试用例,你可以通过下面的指令来运行全部的用例
# 这行命令的执行时间比较长
$ cpan Test::Nginx

# 如果目录已经存在则会先删除再创建
$ export MODULE_TEST_PATH=/path/to/temp/dir

# 如果你安装了动态模块则需要指定动态模块的绝对路径,反之则无需执行这行命令
$ export MODULE_PATH=/path/to/ngx_http_waf_module.so

# 自动化测试
$ cd ./test/test-nginx
$ sh ./init.sh
$ sh ./start.sh ./t/*.t
# 可以使用WRK工具测试
$ wrk -c 100 -d 30m -t 1 -s test/wrk/rand.lua --latency \
    http://localhost/ -- /path/to/rand-str.txt

6注意事项

如需更多帮助,可以参考 常见问题与解答!

本模块只保证对 nginx-1.18.0 或更新的版本的兼容性,且不保证与 Linux 以外的操作系统的兼容性。这里需要注意的是,模块与 ngx_http_rewrite_module 存在兼容性问题。

  • return 指令生效时,该模块不会生效
  • rewrite 指令造成了返回(如 302 重定向)时,该模块不会生效
  • 所以可以使用 try_files 代替 rewrite 指令,避免上述问题的出现
# rewrite
if (!-e $request_filename) {
    rewrite (.*) /index.php
}

# try_files
try_files $uri $uri/ /index.php;

7参考链接

  • Github 代码仓库
  • 黑白名单规则说明
  • 检测项目规则优先级
  • 模块的内置变量
  • 日志相关的配置说明

本文转载自:「 Escape 的博客 」,原文:https://tinyurl.com/2p979waj ,版权归原作者所有。



免责声明:本文内容来源于网络,所载内容仅供参考。转载仅为学习和交流之目的,如无意中侵犯您的合法权益,请及时联系Docker中文社区!


相关推荐

使用 python-fire 快速构建 CLI_如何搭建python项目架构

命令行应用程序是开发人员最好的朋友。想快速完成某事?只需敲击几下键盘,您就已经拥有了想要的东西。Python是许多开发人员在需要快速组合某些东西时选择的第一语言。但是我们拼凑起来的东西在大多数时候并...

Python 闭包:从底层逻辑到实战避坑,附安全防护指南

一、闭包到底是什么?你可以把闭包理解成一个"带记忆的函数"。它诞生时会悄悄记下自己周围的变量,哪怕跑到别的地方执行,这些"记忆"也不会丢失。就像有人出门时总会带上...

使用Python实现九九乘法表的打印_用python打印一个九九乘法表

任务要求九九乘法表的结构如下:1×1=11×2=22×2=41×3=32×3=63×3=9...1×9=92×9=18...9×9=81使用Python编写程序,按照上述格式打印出完整的九...

吊打面试官(四)--Java语法基础运算符一文全掌握

简介本文介绍了Java运算符相关知识,包含运算规则,运算符使用经验,特殊运算符注意事项等,全文5400字。熟悉了这些内容,在运算符这块就可以吊打面试官了。Java运算符的规则与特性1.贪心规则(Ma...

Python三目运算基础与进阶_python三目运算符判断三个变量

#头条创作挑战赛#Python中你学会了三步运算,你将会省去很多无用的代码,我接下来由基础到进阶的方式讲解Python三目运算基础在Python中,三目运算符也称为条件表达式。它可以通过一行代码实现条...

Python 中 必须掌握的 20 个核心函数——set()详解

set()是Python中用于创建集合的核心函数,集合是一种无序、不重复元素的容器,非常适合用于成员检测、去重和数学集合运算。一、set()的基本用法1.1创建空集合#创建空集合empty_se...

15个让Python编码效率翻倍的实用技巧

在软件开发领域,代码质量往往比代码数量更重要。本文整理的15个Python编码技巧,源自开发者在真实项目中验证过的工作方法,能够帮助您用更简洁的代码实现更清晰的逻辑。这些技巧覆盖基础语法优化到高级特性...

《Python从小白到入门》自学课程目录汇总(和猫妹学Python)

小朋友们好,大朋友们好!不知不觉,这套猫妹自学Python基础课程已经结束了,猫妹体会到了水滴石穿的力量。水一直向下滴,时间长了能把石头滴穿。只要坚持不懈,细微之力也能做出很难办的事。就比如咱们的学习...

8÷2(2+2) 等于1还是16?国外网友为这道小学数学题吵疯了……

近日,国外网友因为一道小学数学题在推特上争得热火朝天。事情的起因是一个推特网友@pjmdoll发布了一条推文,让他的关注者解答一道数学题:Viralmathequationshavebeen...

Python学不会来打我(21)python表达式知识点汇总

在Python中,表达式是由变量、运算符、函数调用等组合而成的语句,用于产生值或执行特定操作。以下是对Python中常见表达式的详细讲解:1.1算术表达式涉及数学运算的表达式。例如:a=5b...

Python运算符:数学助手,轻松拿咧

Python中的运算符就像是生活中的数学助手,帮助我们快速准确地完成这些计算。比如购物时计算总价、做家务时分配任务等。这篇文章就来详细聊聊Python中的各种运算符,并通过实际代码示例帮助你更好地理解...

Python学不会来打我(17)逻辑运算符的使用方法与使用场景

在Python编程中,逻辑运算符(LogicalOperators)是用于组合多个条件表达式的关键工具。它们可以将多个布尔表达式连接起来,形成更复杂的判断逻辑,并返回一个布尔值(True或Fa...

Python编程基础:运算符的优先级_python中的运算符优先级问题

多个运算符同时出现在一个表达式中时,先执行哪个,后执行哪个,这就涉及运算符的优先级。如数学表达式,有+、-、×、÷、()等,优先级顺序是()、×、÷、+、-,如5+(5-3)×4÷2,先计算(5-3)...

Python运算符与表达式_python中运算符&的功能

一、运算符分类总览1.Python运算符全景图2.运算符优先级表表1.3.1Python运算符优先级(从高到低)优先级运算符描述结合性1**指数右→左2~+-位非/一元加减右→左3*//...

Python操作Excel:从基础到高级的深度实践

Python凭借其丰富的库生态系统,已成为自动化处理Excel数据的强大工具。本文将深入探讨五个关键领域,通过实际代码示例展示如何利用Python进行高效的Excel操作,涵盖数据处理、格式控制、可视...

取消回复欢迎 发表评论: