把任何一台公网服务器的NGINX错误日志打开,你会看到重复上演的同一幕:针对/wp-login.php、/.env、/phpmyadmin,以及上千个站点上根本不存在的路径,探测请求以404状态码稳定地涌入。漏洞扫描器爬取目录树时,返回的是一堵404高墙;机器人撞击锁定的后台接口时,构筑的是一堵403高墙;撞库攻击运行时,则垒起一堵登录失败的高墙。正常访问几乎从不会制造突发错误,但滥用者产出的几乎只有错误。这种不对称,正是NGINX滥用防护模块所依据的全部信号——而绝大多数服务器把它丢弃了。
常规工具并不能利落地解决这个问题。以limit_req为代表的速率限制器,通过请求量来调节负载,这导致它在流量洪峰期间放缓所有人的请求,而在速率稍微下降的瞬间就立刻将攻击者放了回来。像fail2ban这样的工具,虽然正确地读取到了错误模式,但它们寄生在NGINX之外:它们追踪日志文件,滞后地进行解析,再通过调用shell去操作防火墙,所以封禁指令落地时,往往已是损害发生数秒乃至数分钟后。真正想要的是:读取服务器自身正在返回的状态码,并且立刻在worker内部,驱逐那些流量主要由失败构成的外部访客。
这正是NGINX滥用防护模块所做的事。它观察每个请求的最终响应状态,在工作进程的共享内存中为每个客户端维护一个小巧的记分,一旦客户端跨过错误阈值,就会立即获得一个定时封禁。封禁在NGINX的preaccess阶段生效,发生在一切处理器、文件查找或上游转发运行之前。没有任何边车进程、日志搬运器或脚本层介入。决策完全在编译好的C代码中,于数微秒内完成。以下内容将展示该模块的工作机理、安装与配置方式,以及如何安全地将其部署到线上流量中去。
模块将滥用检测提炼为三个运动部件,它们全都内置于NGINX的工作进程中。首先,每个客户端身份在共享内存区域内仅对应一个单独的细小数字,计算方式采用带泄漏和衰减的记分机制。每匹配一个错误响应,就为这个分数增加对应值;而这个分数本身,也会按照每秒“阈值除以间隔时长”的速率持续流失。一个短促且尖锐的错误突发会瞬间将分数推过红线,触发封禁;但在一小时内缓慢散落出个别404状态的细水长流,则根本积累不到触线值。关键在于,无论将阈值设得多高,记分只占用一条固定大小的记录。所以,哪怕面对僵尸网络抛出数万个不同来源地址,一个容量适中的共享内存区也能从容地追踪它们。
其次,模块在请求生命周期的两个节点上嵌入钩子。一个头部过滤器负责检查每个请求的最终响应状态,并更新违规客户端的记分值。与之并行,在preaccess阶段则检查当前客户端是否已经处于封禁状态。由于preaccess运行在路由选择、静态文件处理和上游代理之前,被列入封禁名单的访客会在处理成本最低的地方被直接拦下——也就是在NGINX执行任何文件查找或后端转发之前,就已被拒绝。这种设计,让服务器仅用极轻量的计算代价,就实现了对恶意流量的即时排斥,而无需借助任何外部守护进程。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.