6月20号F5连更两则安全公告,NGINX主线1.31.0/1.31.1版本爆出两个CVSS v4 9.2分的临界漏洞,一个打HTTP/3 QUIC,一个打HTTP/2代理。算上6月19号刚曝光的rewrite模块堆溢出CVE-2026-42945,三天时间凑齐三个高危,全是远程无认证就能触发的级别。
很多运维刚补完rewrite的补丁,转头又要处理HTTP3和HTTP2的洞。最麻烦的是K8s集群,Ingress Controller的配置散在几十个Namespace里,开发随便加个annotation就可能踩坑,人工排查根本查不过来。
这篇文章把三个漏洞的触发条件、检测脚本、升级步骤、临时缓解全部整理好,单机物理机、Docker容器、K8s集群全场景覆盖,脚本直接复制就能跑。
一、三个漏洞的真实影响范围与触发逻辑
很多人看公告只记住了版本号,没搞懂自己的业务会不会中招。我把三个洞的触发条件、实际危害、覆盖场景全部拆解开,你对着自己的环境对一遍,就能快速判断风险等级。
CVE-2026-42530:HTTP/3 QUIC释放后使用漏洞
这个洞出在ngx_http_v3_module,也就是NGINX官方原生的HTTP/3模块。触发前提只有两个:NGINX版本是1.31.0或者1.31.1,并且配置里显式开启了HTTP/3监听。
现在国内很多站点为了移动端首屏加速,都开了QUIC协议,UDP 443端口直接放公网。这个漏洞是典型的释放后使用(UAF),处理QUIC多路复用的时候,连接结构体被提前释放,后续逻辑还继续引用这块内存。攻击者可以构造连续的QUIC流请求,精准操控内存布局,把恶意数据填到释放后的内存位置。
最坏情况直接远程执行代码,接管整个NGINX进程。就算拿不到shell,发几个构造好的UDP包就能打崩worker进程,造成全站拒绝服务。目前公网扫UDP 443的探测脚本已经扩散,没补的站基本一戳一个死。
覆盖产品不止开源版NGINX,NGINX Plus商业版、NGINX Gateway Fabric、基于官方镜像构建的Nginx Ingress Controller全中。只要底层NGINX基线是1.31.0/1.31.1,开了HTTP3就有风险。
CVE-2026-42055:HTTP/2代理堆缓冲区溢出
这个洞在ngx_http_proxy_v2_module和gRPC代理模块里。触发需要四个条件同时满足,缺一个都打不成:
现在微服务架构里,大量团队用NGINX做gRPC网关,为了兼容业务自定义头,会关掉无效头过滤,再把header缓冲区调大。刚好凑齐四个条件,直接踩坑。
漏洞成因是代理转发HTTP/2响应头的时候,边界校验存在逻辑缺陷,超大响应头会直接溢出到堆内存。攻击者可以控制后端服务返回恶意响应头,触发堆溢出,篡改NGINX进程内存。
别觉得后端服务都是自己的就没事。内网只要有一个服务被拿下,就能通过这个洞打穿网关,横向渗透整个集群。容器环境里ASLR防护经常没拉满,溢出成功率比物理机还高。
CVE-2026-42945:Rewrite模块潜伏18年堆溢出
这个是6月19号曝光的老漏洞,从0.6.27到1.30.0全版本覆盖,覆盖面比前两个广得多。触发条件很简单:rewrite规则里用了$1、$2这类正则捕获变量,并且后面拼接了?号传递参数。
大部分站点的URL重写规则都会这么写,比如旧路径重定向带原有参数、伪静态规则传参。很多人写了五六年的规则从来没出过问题,这次直接爆堆溢出。
这个洞的危害是三个里面最隐蔽的。没人会觉得一个URL重定向能出RCE,但实际测试下来,构造特定长度的请求URL就能触发溢出,远程无认证直接拿shell,目前已经有公开的可利用EXP。
NGINX三漏洞风险判定流程:先校验NGINX版本,再分别匹配每个漏洞的配置触发条件,最终输出风险等级和对应修复路径,照着走一遍就能完成初筛。
二、单机环境一键检测脚本(三漏洞全覆盖)
手动排查就两步:看版本、扫配置。但很多环境改了默认配置路径,套了面板,include了大量分散的配置文件,人工扫很容易漏。
我写了个三合一检测脚本,自动识别NGINX版本,遍历所有加载的配置文件,同时扫描三个漏洞的风险点,按风险等级标色输出。兼容CentOS、Ubuntu、Alpine,物理机和容器内都能直接跑。
#!/bin/bash
# NGINX 三高危漏洞综合检测脚本
# 覆盖:CVE-2026-42530(HTTP3 UAF) / CVE-2026-42055(HTTP2代理堆溢出) / CVE-2026-42945(Rewrite堆溢出)
set -uo pipefail
RED='\\033[0;31m'
YELLOW='\\033[1;33m'
GREEN='\\033[0;32m'
NC='\\033[0m'
echo -e "${GREEN}==== NGINX 三高危漏洞综合检测工具 ====${NC}"
echo "检测目标:CVE-2026-42530 / 42055 / 42945"
echo "———————————————"
# 1. 定位NGINX二进制与配置路径
if command -v nginx &>/dev/null; then
NGX_VER=$(nginx -v 2>&1 | grep -oP 'nginx/\\K[\\d\\.]+')
CONF_PATH=$(nginx -V 2>&1 | grep -oP 'conf-path=\\K[^ ]+')
CONF_DIR=$(dirname "$CONF_PATH")
MODULES=$(nginx -V 2>&1)
else
echo -e "${YELLOW}[警告]未找到nginx命令,默认扫描/etc/nginx目录${NC}"
NGX_VER="unknown"
CONF_DIR="/etc/nginx"
MODULES=""
fi
echo "当前NGINX版本: $NGX_VER"
echo "配置根目录: $CONF_DIR"
# 版本比较函数
ver_ge() {
printf '%s\\n%s' "$2" "$1" | sort -V | head -n1 | grep -xq "$2"
}
ver_lt() {
! ver_ge "$1" "$2"
}
RISK_42530=0
RISK_42055=0
RISK_42945=0
# 版本风险判定
if [ "$NGX_VER" != "unknown" ]; then
# CVE-2026-42945: 0.6.27 ~ 1.30.0
if ver_ge "$NGX_VER" "0.6.27" && ver_lt "$NGX_VER" "1.30.1"; then
RISK_42945=1
echo -e "${RED}[严重] 版本命中CVE-2026-42945 Rewrite堆溢出漏洞${NC}"
fi
# CVE-2026-42530 / 42055: 1.31.0 / 1.31.1
if [ "$NGX_VER" = "1.31.0" ] || [ "$NGX_VER" = "1.31.1" ]; then
RISK_42530=1
RISK_42055=1
echo -e "${RED}[严重] 版本命中CVE-2026-42530/42055 HTTP3/HTTP2双漏洞${NC}"
fi
fi
# 2. 遍历所有配置文件
CONF_FILES=$(find "$CONF_DIR" -type f -name "*.conf" 2>/dev/null)
if [ -z "$CONF_FILES" ]; then
echo -e "${YELLOW}[警告] 未找到.conf配置文件,请手动确认配置路径${NC}"
else
CONF_COUNT=$(echo "$CONF_FILES" | wc -l)
echo "已加载配置文件数量: $CONF_COUNT"
fi
echo -e "\\n${YELLOW}=== 配置风险扫描 ===${NC}"
# 检测CVE-2026-42530:HTTP3/QUIC开启
echo -e "\\n1. HTTP3/QUIC配置检测 (CVE-2026-42530)"
HTTP3_FILES=$(grep -lE 'listen.*http3|quic\\s+on' $CONF_FILES 2>/dev/null || true)
if [ -n "$HTTP3_FILES" ]; then
echo -e "${RED}发现开启HTTP3/QUIC的配置文件:"
echo "$HTTP3_FILES"
echo -e "${NC}"
if [ $RISK_42530 -eq 1 ]; then
echo -e "${RED}版本+配置双命中,存在远程代码执行风险${NC}"
fi
else
echo -e "${GREEN}未发现开启HTTP3/QUIC的配置${NC}"
fi
# 检测CVE-2026-42055:HTTP2/gRPC代理高危配置
echo -e "\\n2. HTTP2/gRPC代理配置检测 (CVE-2026-42055)"
HTTP2_PROXY_FILES=$(grep -lE 'proxy_http_version\\s+2|grpc_pass' $CONF_FILES 2>/dev/null || true)
INVALID_HEADERS_FILES=$(grep -l 'ignore_invalid_headers\\s+off' $CONF_FILES 2>/dev/null || true)
LARGE_HEADER_FILES=$(grep -lE 'large_client_header_buffers.*[2-9][0-9]*M' $CONF_FILES 2>/dev/null || true)
TRIGGER_COUNT=0
[ -n "$HTTP2_PROXY_FILES" ] && TRIGGER_COUNT=$((TRIGGER_COUNT+1))
[ -n "$INVALID_HEADERS_FILES" ] && TRIGGER_COUNT=$((TRIGGER_COUNT+1))
[ -n "$LARGE_HEADER_FILES" ] && TRIGGER_COUNT=$((TRIGGER_COUNT+1))
if [ $TRIGGER_COUNT -eq 3 ]; then
echo -e "${RED}完整命中全部触发条件,存在堆溢出风险"
echo "HTTP2/gRPC代理配置文件: $HTTP2_PROXY_FILES"
echo "关闭无效头过滤配置: $INVALID_HEADERS_FILES"
echo "超大Header缓冲区配置: $LARGE_HEADER_FILES${NC}"
elif [ $TRIGGER_COUNT -gt 0 ]; then
echo -e "${YELLOW}命中${TRIGGER_COUNT}项触发条件,暂不满足完整利用条件,建议同步加固${NC}"
else
echo -e "${GREEN}未发现高危HTTP2代理配置${NC}"
fi
# 检测CVE-2026-42945:危险Rewrite规则
echo -e "\\n3. 危险Rewrite规则检测 (CVE-2026-42945)"
DANGER_REWRITE=$(grep -nE 'rewrite[[:space:]]+.*\\$[0-9]+.*\\?' $CONF_FILES 2>/dev/null || true)
if [ -n "$DANGER_REWRITE" ]; then
echo -e "${RED}发现高危Rewrite规则(捕获变量拼接问号传参):"
echo "$DANGER_REWRITE${NC}"
else
echo -e "${GREEN}未发现危险Rewrite规则${NC}"
fi
# 最终结论
echo -e "\\n${YELLOW}=== 检测结论 ===${NC}"
TOTAL_RISK=$((RISK_42530 + RISK_42055 + RISK_42945))
if [ $TOTAL_RISK -gt 0 ]; then
echo -e "${RED}当前环境存在高危漏洞,建议按以下优先级处理:"
echo "1. 立即升级至安全版本:开源版≥1.31.2,稳定版≥1.26.4"
echo "2. 无法立即升级的,先执行临时缓解措施"
echo "3. K8s环境需同步升级Ingress Controller镜像${NC}"
else
if [ "$NGX_VER" = "unknown" ]; then
echo -e "${YELLOW}未获取到NGINX版本,仅配置扫描无风险,请手动确认版本${NC}"
else
echo -e "${GREEN}当前版本与配置未命中三个高危漏洞${NC}"
fi
fi
使用方式很简单,把脚本存为nginx_cve_scan.sh,执行两条命令就行:
chmod +x nginx_cve_scan.sh
./nginx_cve_scan.sh
输出里红色标注的就是明确命中的风险项,黄色是部分命中需要关注,绿色代表暂未发现问题。如果版本命中但配置没开,也算高风险,别觉得没开HTTP3就万事大吉,模块已经编译进二进制,只是暂时没触发,优先升级才是根本解法。
三、K8s集群批量排查方案
很多运维只盯着物理机的NGINX,忘了K8s集群里的Ingress Controller。现在绝大多数K8s集群都用ingress-nginx或者官方NGINX Ingress Controller,底层全是NGINX。
集群里的坑比单机多得多。首先是镜像版本,很多人用latest或者固定大版本tag,底层NGINX基线早就过时了。其次是配置分散,Ingress的annotation可以在每个Namespace、每个Ingress资源里单独配置,开发随便加个configuration-snippet就能写NGINX规则,运维根本没法统一管控。
我之前遇到过一个集群,二十多个Namespace,上百个Ingress,其中三个业务线偷偷在annotation里开了HTTP3,运维完全不知道,这次漏洞一出直接裸奔。
K8s Nginx Ingress攻击面架构:云厂商LB → 节点端口 → Ingress Controller Pod → 集群内Service → 业务Pod,分别标注三个漏洞的触发位置:HTTP/3漏洞在Ingress的UDP 443监听层,HTTP/2代理漏洞在Ingress到后端gRPC服务的转发链路,Rewrite漏洞在Ingress的URL重写规则处理阶段。
第一步:确认控制器底层NGINX版本
别只看镜像tag,很多镜像tag只标控制器版本,不标底层NGINX版本。直接进Pod里执行命令看最准:
# 替换成你的ingress命名空间和Pod名
kubectl exec -n ingress-nginx ingress-nginx-controller-xxx — nginx -v
社区版ingress-nginx和F5官方NGINX Ingress Controller的版本对应关系不一样,别搞混。拿不准就直接进Pod查,不会出错。
第二步:全集群Ingress注解批量扫描
我写了个批量扫描脚本,遍历所有Namespace的Ingress资源,检测annotation里的危险配置,输出风险项和对应命名空间。依赖kubectl和jq,集群管理员账号直接就能跑。
#!/bin/bash
# K8s Nginx Ingress 三漏洞批量扫描脚本
RED='\\033[0;31m'
GREEN='\\033[0;32m'
YELLOW='\\033[1;33m'
NC='\\033[0m'
echo -e "${GREEN}==== K8s Nginx Ingress 集群漏洞批量扫描 ====${NC}"
# 检查依赖
if ! command -v kubectl &>/dev/null; then
echo -e "${RED}错误:未找到kubectl命令${NC}"
exit 1
fi
if ! command -v jq &>/dev/null; then
echo -e "${RED}错误:未找到jq命令,请先安装jq${NC}"
exit 1
fi
# 1. 扫描控制器镜像
echo -e "\\n${YELLOW}1. Ingress Controller 镜像与版本检测${NC}"
# 尝试常见命名空间
for ns in ingress-nginx nginx-ingress nginx-gateway-fabric; do
PODS=$(kubectl get pods -n $ns -o jsonpath='{.items[*].metadata.name}' 2>/dev/null || true)
if [ -n "$PODS" ]; then
echo "发现命名空间: $ns"
IMAGES=$(kubectl get pods -n $ns -o jsonpath='{.items[*].spec.containers[*].image}')
echo "控制器镜像: $IMAGES"
# 取第一个Pod查底层NGINX版本
FIRST_POD=$(echo $PODS | awk '{print $1}')
NGX_VER=$(kubectl exec -n $ns $FIRST_POD — nginx -v 2>&1 | grep -oP 'nginx/\\K[\\d\\.]+')
echo "底层NGINX版本: $NGX_VER"
if [ "$NGX_VER" = "1.31.0" ] || [ "$NGX_VER" = "1.31.1" ]; then
echo -e "${RED}底层NGINX版本命中42530/42055高危漏洞${NC}"
elif ver_ge "$NGX_VER" "0.6.27" && ver_lt "$NGX_VER" "1.30.1"; then
echo -e "${RED}底层NGINX版本命中42945 Rewrite漏洞${NC}"
fi
fi
done
# 2. 全集群Ingress注解扫描
echo -e "\\n${YELLOW}2. 全集群Ingress高危注解扫描${NC}"
echo "扫描范围:所有Namespace下Ingress的configuration-snippet/server-snippet注解"
RISK_COUNT=0
while IFS= read -r line; do
[ -z "$line" ] && continue
NS=$(echo "$line" | cut -d'|' -f1)
NAME=$(echo "$line" | cut -d'|' -f2)
KEY=$(echo "$line" | cut -d'|' -f3)
VALUE=$(echo "$line" | cut -d'|' -f4-)
# 匹配HTTP3风险
if echo "$VALUE" | grep -qE 'http3|quic\\s+on'; then
echo -e "${RED}[HTTP3高危] ${NS}/${NAME} 注解${KEY}中开启HTTP3${NC}"
RISK_COUNT=$((RISK_COUNT+1))
fi
# 匹配HTTP2代理风险
if echo "$VALUE" | grep -qE 'proxy_http_version\\s+2|grpc_pass' && \\
echo "$VALUE" | grep -q 'ignore_invalid_headers\\s+off' && \\
echo "$VALUE" | grep -qE 'large_client_header_buffers.*[2-9]M'; then
echo -e "${RED}[HTTP2高危] ${NS}/${NAME} 注解${KEY}命中堆溢出条件${NC}"
RISK_COUNT=$((RISK_COUNT+1))
fi
# 匹配Rewrite风险
if echo "$VALUE" | grep -qE 'rewrite[[:space:]]+.*\\$[0-9]+.*\\?'; then
echo -e "${RED}[Rewrite高危] ${NS}/${NAME} 注解${KEY}存在危险重写规则${NC}"
RISK_COUNT=$((RISK_COUNT+1))
fi
done < <(kubectl get ingress –all-namespaces -o json | jq -r '
.items[] |
.metadata.namespace as $ns |
.metadata.name as $name |
.metadata.annotations |
to_entries[] |
select(.key | test("snippet")) |
[$ns, $name, .key, .value] | join("|")
')
echo -e "\\n${YELLOW}扫描完成,共发现${RISK_COUNT}项风险配置${NC}"
if [ $RISK_COUNT -gt 0 ]; then
echo "请先修改对应Ingress注解临时缓解,再升级控制器镜像"
else
echo -e "${GREEN}未在Ingress注解中发现高危配置${NC}"
fi
第三步:NGINX Gateway Fabric 额外排查
如果你的集群用了NGINX Gateway Fabric(F5新推的Gateway API实现),还要单独查Gateway资源的配置。执行这条命令就能看到所有网关的HTTP3开启情况:
kubectl get gateways.gateway.networking.k8s.io -A -o json | jq -r '.items[] | .metadata.namespace + "/" + .metadata.name + ": " + (.spec.listeners[] | select(.protocol=="HTTP3") | .port | tostring)'
Gateway Fabric 2.6.3及之前版本都受影响,直接升级到2.6.4及以上就能修复。
四、全场景升级修复操作指南
升级是唯一能彻底修复三个漏洞的方式,临时缓解只能应急。我把常见环境的升级步骤全部整理好,照着执行就行。
CentOS/Rocky Linux 物理机/虚拟机
系统默认源的NGINX版本普遍偏旧,必须先加官方源才能拿到最新安全版。
# 安装官方源包
dnf install https://nginx.org/packages/centos/9/x86_64/RPMS/nginx-release-centos-9-0.el9.ngx.noarch.rpm -y
# 清缓存并升级
dnf clean all
dnf makecache
dnf update nginx -y
# 校验配置并重载
nginx -t
systemctl reload nginx
# 确认版本
nginx -v
如果是CentOS 7,把源地址里的9换成7就行。升级前最好备份一下配置目录,避免意外。
Ubuntu/Debian 系列
同样先加官方源,再执行升级:
# 导入官方GPG密钥
curl -fsSL https://nginx.org/keys/nginx_signing.key | gpg –dearmor -o /usr/share/keyrings/nginx-archive-keyring.gpg
# 添加官方源
echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] http://nginx.org/packages/ubuntu $(lsb_release -cs) nginx" > /etc/apt/sources.list.d/nginx.list
# 升级
apt update
apt install nginx -y
# 校验重载
nginx -t
systemctl reload nginx
Alpine Linux
Alpine容器环境用apk升级就行:
apk update
apk add –upgrade nginx
nginx -v
如果是自己构建的Alpine镜像,把Dockerfile里的apk add nginx改成指定版本,或者每次构建前update。
Docker 容器环境
别用latest标签,固定到具体安全版本。基础镜像直接替换成官方安全版:
# 修复前
FROM nginx:1.31.1
# 修复后
FROM nginx:1.31.2
修改完重新构建镜像,推到私有仓库,再滚动更新容器。升级前一定要用新镜像在测试环境跑一遍配置校验,避免语法不兼容。
K8s Ingress Controller 升级
社区版 ingress-nginx(Helm 方式)
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
# 升级前先查可用版本,确认底层NGINX基线≥1.31.2
helm search repo ingress-nginx/ingress-nginx –versions
# 执行升级
helm upgrade ingress-nginx ingress-nginx/ingress-nginx \\
–namespace ingress-nginx \\
–set controller.replicaCount=2 \\
–set strategy.rollingUpdate.maxUnavailable=0
F5官方 NGINX Ingress Controller
直接修改Deployment的镜像tag到最新安全版本,执行滚动更新:
kubectl set image deployment/nginx-ingress nginx-ingress=nginx/nginx-ingress:3.7.2 -n nginx-ingress
升级完一定要重新跑一遍集群扫描脚本,确认风险全部消除。滚动更新过程中 watch 一下Pod状态,出现CrashLoopBackOff立刻回滚。
五、无法立刻升级的临时缓解方案
有些业务不能随便重启,或者变更窗口还没到,可以先做临时缓解,挡住已知的攻击路径。但临时方案最多撑一周,必须排期升级。
CVE-2026-42530 缓解
两种方式二选一,推荐第一种:
CVE-2026-42055 缓解
四个触发条件破坏任意一个就行,推荐改前两个,对业务影响最小:
# 开启无效头过滤(默认就是on,确认没被改成off就行)
ignore_invalid_headers on;
# 限制单缓冲区大小为1M,低于2M阈值
large_client_header_buffers 4 1M;
如果业务不依赖HTTP/2代理,也可以直接把proxy_http_version 2改成1.1,彻底关闭HTTP2转发。gRPC服务不能改,只能用前两种方式。
CVE-2026-42945 缓解
重构危险的rewrite规则,不要用捕获变量直接拼接问号。举个例子:
# 危险写法(触发漏洞)
rewrite ^/article/(.*)$ /index.php?id=$1 last;
# 安全写法(用set中转,避免直接拼接)
set $article_id $1;
rewrite ^/article/(.*)$ /index.php?id=$article_id last;
# 更推荐的写法(传递全部参数用$args)
rewrite ^/old/(.*)$ /new/$1?$args permanent;
批量改规则的时候,用脚本扫出来的结果逐个核对,别漏了include的子配置。
六、漏洞底层技术原理拆解
这部分偏底层,适合安全从业者和资深运维看,只想修漏洞的可以跳过。搞懂原理才能判断自己的防护有没有用,不会被各种危言耸听的传言带偏。
CVE-2026-42530:QUIC连接复用UAF
NGINX的HTTP/3模块自研了QUIC协议栈,处理连接迁移和流复用的时候,引用计数逻辑存在错误。当客户端快速创建并关闭多个QUIC流,同时触发连接拥塞控制的回调函数时,ngx_http_v3_connection_t结构体的引用计数会提前减到0,触发内存释放。
但流处理的回调链里还持有这个结构体的指针,后续执行就会访问已经释放的内存。这就是典型的UAF漏洞。
攻击者可以精准控制发包时序,结构体释放后立刻发送新的流请求,分配新的内存块落到同一个地址。后续回调引用的时候,读到的就是攻击者构造的恶意数据,篡改函数指针后就能劫持进程执行流。
因为QUIC是UDP协议,无连接状态,攻击者可以反复发包调整内存布局,不需要维持稳定连接,普通WAF很难拦截这种探测流量。
CVE-2026-42055:HTTP/2响应头堆溢出
HTTP/2代理模块在处理后端返回的响应头时,会先分配一块堆内存存储解析后的头信息。计算缓冲区长度的时候,代码没有对HTTP/2的伪头字段(:status、:content-type这类)做正确的长度统计,导致计算出的缓冲区长度比实际需要的小。
当后端返回超大的自定义响应头时,实际写入的数据长度超过分配的内存大小,直接溢出到相邻的堆块。
触发条件里的ignore_invalid_headers off是关键开关。默认情况下NGINX会丢弃格式无效的响应头,关掉之后所有头都会被接收解析,刚好能触发溢出。large_client_header_buffers >2M是为了保证分配到足够大的堆块,溢出的长度足够覆盖到关键的函数指针。
这个漏洞属于反向溢出,攻击流量从后端服务发往网关,很多防护设备只检测入站请求,不校验出站响应,刚好能绕过去。
CVE-2026-42945:Rewrite长度计算整数溢出
rewrite模块在解析替换字符串的时候,会先计算最终生成的URL长度,再分配对应大小的缓冲区。当替换字符串里同时包含正则捕获变量和问号?的时候,长度计算逻辑存在整数溢出。
具体来说,代码在统计问号和参数长度的时候,少加了一个字节的偏移,当捕获字符串长度达到特定值时,计算出的总长度会发生整数回绕,变成一个很小的值。分配的缓冲区远小于实际写入的数据,最终触发堆溢出。
这个bug从2008年的版本就存在,藏了18年没人发现。因为正常业务请求的URL长度不会刚好卡在溢出阈值上,只有构造特定长度的请求才能触发。现在公开的EXP已经优化了利用链,稳定RCE的成功率很高。
七、长期安全加固体系
修漏洞只是治标,建立完整的防护体系才能避免下次踩坑。我把落地过的加固方案拆成四部分,中小团队也能直接照搬。
NGINX网关安全加固体系架构从接入层、网关层、运维管控层、安全监控层四个维度展示完整加固方案,包含防火墙策略、配置基线、自动化巡检、异常告警等具体措施的落地位置。
版本与镜像管理
生产环境优先用稳定分支,比如1.26.x,主线版本只在测试环境验证新功能。别盲目追新,主线版本出高危漏洞的概率远高于稳定版。
每个季度做一次版本基线巡检,跟进F5的安全公告,高危补丁72小时内完成评估,一周内完成全量升级。
镜像仓库建立版本黑名单,把存在高危漏洞的NGINX版本全部加入禁止列表。K8s集群用OPA或者Kyverno做准入控制,旧版本镜像直接禁止调度。
配置安全基线
HTTP3不要全站开,只给移动端核心域名开。UDP 443端口只放行国内主流运营商的IP段,境外IP直接在防火墙层拦截。配置里强制开启quic_retry on,做地址验证,减少伪造源地址的攻击。
HTTP/2代理统一规范:ignore_invalid_headers强制开on,large_client_header_buffers单缓冲区最大1M,禁止私自调大。gRPC代理单独出配置模板,不允许业务自定义头大小。
rewrite规则走审批流程,禁止在捕获变量后直接拼接问号传参,统一用$args或者$query_string传递参数。正则表达式做长度限制,避免恶意超长URL触发溢出。
K8s集群里禁用普通业务角色修改configuration-snippet和server-snippet注解。用准入控制器校验所有Ingress配置,命中危险规则的直接拒绝创建,从源头堵死乱加配置的情况。
自动化巡检体系
把单机检测脚本加到每台服务器的crontab,每天凌晨跑一次,结果上报到监控系统,出现风险立刻发告警。
K8s集群的扫描脚本集成到CI/CD流水线,每次Ingress变更都自动扫一遍,有问题直接卡审批。每个星期跑一次全集群扫描,覆盖所有Namespace,避免漏网之鱼。
监控与应急响应
监控NGINX worker进程的异常退出,短时间内多次重启立刻告警,大概率是有人在打漏洞。
监控UDP 443端口的流量异常,短时间内大量不同源IP的小包,基本就是漏洞扫描。配置阈值告警,超过阈值自动拉黑源IP。
开启NGINX的core dump配置,万一进程崩溃了能保留dump文件,分析确认是漏洞攻击还是业务bug。应急响应的时候,dump文件是定位问题的关键。
八、常见踩坑与排障
升级和排查过程中容易遇到各种问题,我整理了高频出现的坑和对应的解决方法。
升级后NGINX启动失败,提示模块不兼容
很多环境编译了第三方模块,比如lua模块、缓存模块、WAF模块。升级NGINX主程序后,模块版本和主程序不匹配,就会启动失败。升级前先确认第三方模块有没有对应新版本的编译包,或者提前重新编译模块。生产环境尽量少用第三方模块,减少依赖链,出问题排查也快。
关了HTTP3之后移动端用户投诉加载慢
HTTP3对弱网环境的加载速度提升很明显,关了之后体验下降是正常的。这只是临时缓解,优先升级到安全版本,升级完重新开HTTP3就行。过渡阶段可以先给核心业务域名开,非核心域名先关,把影响降到最低。
K8s升级Ingress Controller之后出现502
大概率是新版本的配置语法有变化,或者自定义的snippet规则不兼容。升级前一定要在测试集群验证一遍,滚动更新的时候设置maxUnavailable=0,保留旧版本Pod,出现问题立刻回滚。别直接全量替换,很容易炸全站。
脚本扫出来很多rewrite规则,分不清哪些真的危险
只要rewrite指令的替换字符串里,同时出现$数字形式的捕获变量和问号?,就算高危。比如rewrite ^/a/(.*)$ /b/$1?c=1 last;就是危险写法,rewrite ^/a/(.*)$ /b/$1 last;没有问号就没事。拿不准的就把问号后面的参数改成用$args传递,肯定不会错。
内网环境没有外网,没法升级包
提前在有网的环境下载好官方RPM/DEB包,传到内网源服务器,走内网源升级。容器环境提前拉取安全镜像,推到私有镜像仓库,别等到漏洞爆了才发现内网拉不了镜像。
你们线上的NGINX开了HTTP3吗?这次三个漏洞里你最先处理的是哪个?欢迎在评论区说下你的排查进度。
如果升级过程中遇到配置不兼容的问题,也可以留言说下具体场景,我会逐个回复。






