Buzeli
buzeliSoluções Digitais
安全

Cloud Armor已启用,30天内拦截139次攻击——但零真实流量通过:GCP中DNS直连VM如何绕过WAF

发布于 2026年5月3日

看似受保护的基础设施

客户的GCP基础设施一切就位:us-west1-c区域的6个Compute Engine实例、一个200 GB SSD的Cloud SQL MySQL 8.0,以及IP为198.51.100.19的Cloud Load Balancer。Cloud Armor策略已应用于LB后端,OWASP规则处于激活状态——日志显示有活动:30天内139次拦截,全部是真实攻击(LFI、PHP RCE尝试、扫描器)。

初看令人放心。WAF在运行、在拦截,没有误报。直到分析了DNS。

复制
# 通过Cloudflare API验证的DNS记录
# www.client-media.com.br → 198.51.100.200(VM直接IP,proxied=True)
# client-media.com.br     → 198.51.100.200(VM直接IP,proxied=True)
# GCP LB地址:198.51.100.19 — 不在当前流量路径上

已应用Cloud Armor的GCP负载均衡器在IP 198.51.100.19上。DNS指向198.51.100.200——VM的直接IP。真实用户流量从未经过LB。日志中的139次拦截来自扫描器,它们不知何故发现了LB的IP——这对生产流量没有提供任何保护。

WAF配置正确,应用于正确的后端,规则运行正常——对真实流量完全无关紧要。Cloud Armor保护应用程序的唯一要求是流量必须经过LB。如果DNS不指向LB,就没有保护。

为什么之前的修复尝试失败了

这不是第一次诊断出这个问题。之前一次将DNS指向LB的尝试因产生404错误而被回滚。那个第二个问题的根本原因在nginx配置中被识别出来:

复制
# nginx中的server_name — 有问题的配置
server {
    listen 80;
    server_name client-media.com.br;   # 只有根域名
    # www.client-media.com.br 缺失
    ...
}

当DNS指向LB时,带有Host: www.client-media.com.br的请求到达nginx时没有匹配的server_name。nginx回落到默认服务器并返回404。表面上的修复是"回滚DNS"——而真正的修复是在切换之前将www添加到server_name中。

这里的失败模式在任何云中都相同:安全修复(WAF)和路由修复(nginx)需要协调进行。只做其中一个就会产生回滚,让WAF在接下来几个月继续毫无用处。

反模式:WAF在LB上,DNS直连VM

这种模式比看起来更常见,存在于所有云中,不仅仅是GCP:

GCP: Cloud Armor应用于HTTP(S)负载均衡器后端,但DNS指向Compute Engine实例的外部IP。

AWS: WAF关联到ALB,但域名直接指向EC2 IP或旧的ELB。

Cloudflare WAF: Cloudflare代理上的保护已激活,但服务器的80/443端口直接暴露在互联网上——源站拉取绕过了代理。

在所有情况下,绕过向量都是相同的:DNS或网络配置创建了一条绕过安全控制的路径。WAF只处理流经它的流量。

复制
# 快速检查:流量是否经过WAF?

# GCP:检查LB是否在路径中
gcloud compute forwarding-rules list --format="table(name,IPAddress,target)"
dig +short www.client-media.com.br

# 如果dig返回的IP != LB IP,WAF不在路径中

# AWS:检查域名是否解析到ALB
nslookup www.mysite.com.br
# 应该返回ALB DNS(*.elb.amazonaws.com),而不是EC2 IP

# Cloudflare:检查是否已代理(控制台中的橙色云图标)
# IP应返回104.x.x.x(Cloudflare范围),而不是服务器IP

第二个关键风险:Cloud SQL没有PITR

在基础设施审计过程中,发现了第二个关键风险——与WAF无关,但同样严重:

复制
# Cloud SQL — 可用性和备份配置
# 可用性:ZONAL(另一个区域没有副本)
# 二进制日志:已禁用
# 自动备份:每天03:00 UTC,保留7天 — 全部成功

# 禁用二进制日志的后果:
# - 时间点恢复(PITR)不可用
# - 发生数据损坏或意外删除时,
#   只能恢复到最后一次每日备份
# - 潜在数据丢失:最多24小时

在ZONAL可用性和禁用二进制日志的情况下,数据损坏或意外删除事件中的数据丢失窗口最长为24小时——每日备份之间的时间间隔。对于具有事务数据的系统,这意味着当天所有交易都可能丢失。

同一客户发现了两个关键风险,都在单次审计中被发现:WAF没有保护真实流量,数据库没有PITR。两者都没有产生任何告警。如果不进行主动审计,两者都是不可见的。

协调一致的修复计划

修复WAF绕过需要按正确顺序进行三项协调变更:

1. Nginx: 在任何DNS变更之前,将www.client-media.com.br添加到server_name。

2. 证书: 验证LB上的SSL证书是否覆盖www域(LB上的前一个证书已过期——切换前需要新证书)。

3. DNS: 只有在nginx和证书都验证完毕后,才将www和根域指向LB IP(198.51.100.19)。

复制
# 步骤1:修复nginx(在DNS变更之前)
# 编辑 /etc/nginx/sites-available/client-media.com.br
server {
    listen 80;
    listen 443 ssl;
    server_name client-media.com.br www.client-media.com.br;
    ...
}
nginx -t && nginx -s reload

# 步骤2:验证nginx通过LB响应www
curl -H "Host: www.client-media.com.br" http://198.51.100.19/
# 应该返回200,而不是404

# 步骤3:只有在此之后才进行DNS切换
# www.client-media.com.br → 198.51.100.19
# client-media.com.br     → 198.51.100.19

对于Cloud SQL:启用二进制日志和配置区域可用性(另一个区域的副本)需要一个维护窗口并重启实例。两项变更都记录在客户的风险地图中,作为待执行的关键风险。

如何审计您的WAF是否真正在流量路径上

最简单的检查:DNS解析的IP应该是您的WAF/代理/LB的IP——而不是源服务器的IP。

复制
# 测试1:比较DNS IP与LB IP
DOMAIN="www.mysite.com.br"
DNS_IP=$(dig +short $DOMAIN | head -1)
LB_IP="您的LB IP"

if [ "$DNS_IP" = "$LB_IP" ]; then
    echo "正常:流量经过LB/WAF"
else
    echo "警告:DNS解析为 $DNS_IP,LB在 $LB_IP — WAF可能被绕过"
fi

# 测试2(GCP):检查Cloud Armor中的真实访问日志
# 如果有合法流量(真实用户代理、多样化的巴西IP),
# Cloud Armor就在路径上。
# 如果日志只显示机器人/扫描器,真实流量正在直接通过。
gcloud logging read   'resource.type="http_load_balancer" AND jsonPayload.enforcedSecurityPolicy.name="policy-www-client-media-com-br"'   --limit=20   --format="table(timestamp,jsonPayload.remoteIp,jsonPayload.requestUrl,jsonPayload.enforcedSecurityPolicy.outcome)"

一个只显示扫描器拦截而从未记录合法浏览的WAF(正常路径、浏览器用户代理、真实用户IP)——是真实流量正在走另一条路径的信号。

经验教训:路径位置是零号要求

Cloud Armor、AWS WAF、Cloudflare——都是内联控制。它们只保护流经它们的流量。无论策略配置多好、规则多精细、误报率多低:如果DNS不指向WAF,该策略对真实流量就不存在。

基础设施安全审计不仅需要验证控制配置,还需要验证流量路径。在有DNS变更历史、部分迁移或由不同团队在不同时间进行配置的项目中,DNS绕过是最容易创建且最难察觉的风险之一。

30天内139次拦截看起来像保护的证据。它们是扫描器发现了LB IP的证据。真实流量——用户、购买者、Google爬虫——从未经过WAF。