
上个月我做了一次例行的应用防护基线检查。后端是一台跑着Nginx的测试服务前面挂了ALBALB上挂了AWS WAF并且打开了AWS提供的基础托管规则组。按我原来的预期一般的目录枚举和扫描请求早就该被拦住了。结果用ffuf对着自己这个站点跑了一遍后发现接近九成请求都被WAF放行了。仔细翻WAF日志逐条请求都干净得像普通GET没有任何漏洞特征。从那天起我开始认真研究到底怎么在AWS WAF里把ffuf这类高速模糊测试工具的流量识别出来形成一套靠谱的拦截策略。这篇文章就是我这次调优过程的完整记录包括流量观察、规则设计、控制台配置、验证方法以及后来上线后踩过的误伤坑。内容主要面向正在维护云上Web业务的运维和安全工程师如果你也遇到过WAF开着等于没开的情况这篇应该能帮你省不少时间。1. 为什么默认托管规则拦不住 ffuf先看清这个对手先说结论不是AWS WAF太弱而是ffuf这类工具的流量行为跟传统漏洞扫描器完全不是一回事。1.1 实验环境与基线测试流程我在自建测试环境里验证了一遍结构很简单一台EC2上面跑Nginx放了一个只有静态页面的测试站Nginx前面挂ALBALB上绑定了WAF Web ACLWeb ACL开启了AWSManagedRulesCommonRuleSet、AWSManagedRulesSQLiRuleSet、AWSManagedRulesKnownBadInputsRuleSet这几个最常见的托管规则组默认动作是 Allow规则命中Block。然后我用ffuf对测试站点跑目录枚举字典大概几千条线程数保持默认。命令大致是ffuf -u https://your-alb.example.com/api/FUZZ -w wordlist.txt -mc all注意这是在我自己的测试环境、自有资产上做的授权验证。ffuf这类工具用在别人的线上业务上性质完全不同大家一定要分清边界。跑完以后去WAF日志里看结果很直观请求基本全部Allowed只有极少数路径因为包含常见漏洞特征被托管规则截住。换句话说ffuf的默认行为几乎完美绕过了托管规则组的检测面。1.2 ffuf 流量到底长什么样我抓了一部分日志做对比归纳出三个非常明显的特征。第一个是User-Agent。ffuf默认的UA只有一个词fuzz。这个指纹太显眼了在后端日志里按UA排序可以看到成片的fuzz请求连续刷屏。这是单条流量里最容易识别的信号。第二个是高并发。ffuf默认就是并发爆破毫秒级连续发出请求。同一秒内几十个请求打到同一个域名上而且路径完全不重复这是正常人肉操作很难做到的时间分布。第三个是Header结构极简。浏览器发一个普通GET请求会带上Accept、Accept-Language、Accept-Encoding、Connection、Sec-Fetch-Site、Sec-Fetch-Mode等一连串Header。而ffuf发出的请求基本只有Host和User-AgentCookie、Referer、Sec-Fetch-* 这一类字段全都缺失。如果只看单条请求的Body它既没有SQL注入字符串也没有XSS payload托管规则当然不会觉得它有问题。但把这三条拼在一起看这流量根本就不像一个真人。1.3 为什么 AWS 托管规则会漏掉这类行为AWS托管规则组的定位是检测已知漏洞利用特征。CommonRuleSet主要看请求里有没有SQL注入、XSS、路径穿越、已知恶意输入这些具体内容。它面向的是攻击发生时的payload长什么样而不是这个访问者是不是异常机器流量。ffuf做的事情是路径遍历、资源发现它的每条请求里没有明显攻击特征。你拿它跑/admin、/backup、/.git这些路径服务器顶多返回404托管规则根本不会认为这算入侵。再加上规则组默认是Allow模式只要没有明确命中请求就放过去了。明白了这个盲区再去设计规则就有方向了不能只依赖单条请求里有没有攻击载荷必须从行为维度去补。这个思路也是后面所有规则组合的底层逻辑。2. 从指纹到检测维度ffuf 流量特征的四个观察角度要把一个扫描器拦下来先得把它的特征量化成WAF能理解的条件。AWS WAF v2的规则本质上就是布尔表达式你给它几个判断条件它按逻辑组合后返回Allow、Block、Count、Captcha这些动作。所以问题变成哪些维度能作为判断条件哪些维度容易误伤。2.1 User-Agent 指纹最直接的第一道门ffuf默认UA是fuzz这条规则做起来零成本。AWS WAF里加一条ByteMatch规则匹配Header中的User-Agent包含fuzz字样动作设Block就能拦住绝大多数默认配置的ffuf请求。但这里必须说清楚一个前提UA太容易伪造了。ffuf自带-ua参数攻击者完全可以改成Chrome的UA再来跑一轮。所以UA规则只能算第一道门它承担的是低成本拦截默认行为的职责不能作为唯一依赖。我在日常巡检中会把UA作为一个快速指标如果后端日志里突然出现某种UA聚集性上涨先拉出来看看是不是扫描行为然后再决定要不要针对这个UA单独加规则。但它不是终点。2.2 Header 完整度判断像不像真实浏览器真实用户通过浏览器访问网站时浏览器会自动附加各种Header这是客户端长期演化的结果。而ffuf这类Go语言写的工具默认请求里不会有这些浏览器特属字段。用一个很粗略的模板去看正常浏览器的GET请求通常包含Accept-Language表示用户的语言偏好Sec-Fetch-Site和Sec-Fetch-Mode表示这次导航的上下文Cookie除非是全新会话一堆以Sec-Ch-Ua开头的客户端提示字段。ffuf默认请求里这些都没有。这里有个实战里的坑直接在WAF规则里做缺失Header即拦截很容易误伤。手机原生App、HTTP客户端脚本、监控探针的请求往往也不带这些浏览器字段它们都是合法业务流量。所以我的建议是Header完整度不要单独成规则更适合做组合条件里的辅助信号跟其他维度叠加使用后误伤率会明显下降。2.3 URL 路径模式扫描器行走的痕迹ffuf靠字典遍历路径这就决定了它产生的URL有很强的试探感。正常用户的访问路径通常有清晰意图而扫描器会在短时间内打出大量随机路径其中相当一部分是敏感目录扫描比如.git、.env、backup、config.php、phpinfo、swagger、actuator、server-status这类。检测这个维度用正则最合适。我把常见敏感路径整理成一个Regex Pattern Set所有命中这个集合的请求都打上可疑标签。不过这类规则同样有误伤风险比如一个真实的线上管理后台路径包含/admin/管理员正常访问也会命中正则。所以路径维度的规则策略是高覆盖率、低判定权它负责缩小检查范围真正的动作交给组合规则或速率规则去决定。2.4 请求速率与时间分布行为维度的关键如果说UA和路径看的是单条请求长什么样速率看的就是整体行为像不像机器。ffuf默认并发很高几百条请求可以在几十秒内全部打完真人不可能做到。AWS WAF自带速率规则最基本的形式是统计单个IP在5分钟窗口内的请求总数超过阈值就执行Block。这个功能单独用很容易踩坑——一个公司出口IP可能承载几百号人正常办公流量5分钟内就能超过一个相对严格的阈值。所以我在配置速率规则时强烈建议加上ScopeDownStatement让WAF只统计可疑路径的请求而不是所有请求。这样既保留了速率检测的能力又把正常用户的日常请求排除在计数范围之外。四个维度总结下来可以这样理解检测维度识别能力误伤风险适合的角色UA指纹高但易伪造低前置快速拦截Header完整度中高组合条件辅助URL路径模式中中缩小检查范围请求速率高中到高组合条件主判据3. AWS WAF 规则组合设计单条匹配到信号叠加清楚了维度再落到规则设计。我的整体思路是精确规则优先模糊规则兜底速率规则压轴。下面这几条规则都来自真实验证你可以直接对照着配置。3.1 规则A拦截ffuf默认UA指纹第一步先解决最明显的暴露面。在Web ACL里添加一条常规规则检查请求头User-Agent匹配方式设为包含字符串fuzz动作直接Block。如果用JSON描述大概是这样{ Name: block-fuzz-default-ua, Priority: 10, Action: { Block: {} }, Statement: { ByteMatchStatement: { SearchString: fuzz, FieldToMatch: { SingleHeader: { Name: user-agent } }, TextTransformations: [ { Priority: 0, Type: LOWERCASE } ], PositionalConstraint: CONTAINS } } }注意SearchString在API层需要做Base64编码在控制台里直接填明文就行。我加上LOWERCASE转换是为了避免ffuf某些版本把UA写成大写时漏掉。配置完后我立刻跑了一轮ffuf效果立竿见影请求返回403WAF的Sampled requests里能看到命中记录。但我知道这只是第一层如果对方在ffuf命令里加了-ua Mozilla/5.0这条规则就废了。所以继续往下加。3.2 规则B可疑路径加白名单排除的组合第二层规则针对路径。我把常见的敏感路径正则做进Regex Pattern Set然后让WAF去匹配URI路径。正则内容大概包括\.git|\.env|\.svn|config\.php|\.bak|backup|dump|phpinfo|swagger|actuator|server-status这里强调一点正则规则单独使用很容易误伤正常业务。比如你线上有个/api/backup接口用户正常调用也会命中backup关键词。所以我在规则B里加了一个组合条件——只有命中可疑路径且来源IP不在内部白名单IP Set中才执行动作。JSON结构如下{ Name: block-suspicious-path-not-whitelist, Priority: 20, Action: { Count: {} }, Statement: { AndStatement: { Statements: [ { RegexPatternSetReferenceStatement: { ARN: arn:aws:wafv2:region:account:regional/regexpatternset/suspicious-path/xxx, FieldToMatch: { UriPath: {} }, TextTransformations: [ { Priority: 0, Type: LOWERCASE } ] } }, { NotStatement: { Statement: { IPSetReferenceStatement: { ARN: arn:aws:wafv2:region:account:regional/ipset/internal-whitelist/xxx } } } } ] } } }我在这条规则上先用Count而不是Block是因为路径正则是典型的低精度高覆盖规则。把它设成Count的另一个好处是WAF会通过Label把命中的请求标记出来后续规则可以引用这个Label做进一步判断。灰度稳定后再把Action切换成Block。3.3 规则C限定了统计范围的速率规则第三条规则解决改UA后的ffuf。这类工具的并发模式不会因为改UA就消失所以速率规则是真正能兜底的防线。AWS WAF的速率规则支持ScopeDownStatement也就是只对满足条件的请求计数。我把ScopeDownStatement指定为命中可疑路径正则再设置5分钟窗口和请求数阈值。5000条字典的ffuf扫描按默认并发几秒钟就能打满阈值而正常用户5分钟内访问几千次可疑路径基本不存在。JSON参考{ Name: rate-limit-suspicious-path, Priority: 30, Action: { Count: {} }, Statement: { RateBasedStatement: { Limit: 2000, EvaluationWindowSec: 300, AggregateKeyType: IP, ScopeDownStatement: { RegexPatternSetReferenceStatement: { ARN: arn:aws:wafv2:region:account:regional/regexpatternset/suspicious-path/xxx, FieldToMatch: { UriPath: {} }, TextTransformations: [ { Priority: 0, Type: LOWERCASE } ] } } } } }这里Limit的值要根据业务量级调。保守一点的做法是先设成3000到5000跑一周看正常业务有没有触发再往下压。如果在按可疑路径计数的情况下正常流量还能触发这个阈值那说明你线上业务大概率本身就被各种爬虫骚扰了这个问题比WAF配置本身更值得警惕。3.4 托管规则组兜底用 Bot Control 处理其他自动化流量自定义规则解决的是ffuf这一个具体工具但站点的扫描来源远不止ffuf。所以我额外开启了AWS的Bot Control托管规则组。它擅长识别更通用的自动化特征比如无头浏览器、检测到bot信号、请求特征不一致等情况。在配置托管规则组时建议先把动作设为Count进监控状态跑几天。确认它在准确识别异常流量、且不影响正常用户的情况下再逐步把对应规则动作切到Block。这类托管规则是按流量计费的开通前先评估一下站点的实际请求量别等月底账单出来才后悔。3.5 规则优先级怎么排AWS WAF按Priority值从小到大依次评估规则先命中先执行。默认动作是Allow所以排在后面的规则只在前面规则都没命中时才会被评估。我的推荐排序是优先级规则名作用1内部白名单IP Set放行办公网、运维跳板机10block-fuzz-default-ua拦截ffuf默认UA20block-suspicious-path-not-whitelist拦截可疑路径30rate-limit-suspicious-path处理改UA后的扫描流量40Bot Control托管规则组兜底其他自动化流量白名单放在最高优先级是为了保证规则误伤时还能有明确逃生通道。高精度的规则往前放低精度高影响的规则往后放整体误伤风险就可控了。4. 灰度上线与真机验证从 Count 到 Block 的完整操作链路规则设计好之后最大的忌讳就是直接切Block上线。我在这个过程里走过弯路现在把完整的部署和验证流程整理出来。4.1 创建 Web ACL 并关联 ALB第一步先确认Web ACL的作用域。AWS WAF里CloudFront和区域资源是两套管理逻辑如果防护对象是CloudFront分布Web ACL必须创建在us-east-1不管你的CloudFront业务在哪个区域如果防护对象是ALB、API Gateway、AppSync等区域资源Web ACL要创建在资源所在的区域。我这次防护的是ALB所以直接在ALB所在区域创建Web ACL。创建时默认动作选Allow这一步很重要默认动作选Block会在规则都没命中时把所有流量拦掉灰度阶段的访问会瞬间断掉。创建完成后在Web ACL的Associated resources里添加ALB。同一个账户里一个区域下默认可以关联多个资源但同一个ALB只能关联一个Web ACL。4.2 新规则先进 Count 模式观察不管规则设计得多自信我都建议先把Action全部设置成Count跑至少一天正常业务观察WAF控制台里的Sampled requests。这个功能会抽样展示最近收到的请求、命中了哪些规则、最终动作是什么。如果Count模式的规则里出现了大量正常用户请求说明这条规则的口径太宽得先收紧再上线。我在配置路径正则规则时第一次就发现Count样本里有几个正常请求命中backup关键词因为接口名里确实带了这个词。后来把正则模式改得更严格比如要求路径包含backup的同时不能是已存在的业务URL才把误报压下去。这种问题不通过Count模式观察根本发现不了。4.3 用 ffuf 做模拟攻击验证规则切到Block后重新跑一轮ffuf。验证时注意看两个地方第一看响应码分布。WAF的Block动作默认返回403所以ffuf的结果里会出现大量403响应。如果还是大面积200和404那说明规则没有生效或者请求流量根本没走到WAF。第二看Sampled requests和日志。进入Web ACL的Sampled requests页面能看到被抽样请求命中的规则ID和动作。确认命中的规则是预期的那几条而不是误打误撞被别的规则拦住。我还做过一次对比测试把ffuf的UA改成Chrome之后再跑验证规则B和规则C是否能兜住。结果显示路径正则规则和速率规则都能生效这说明整套规则组合确实不依赖单一指纹。4.4 用 Athena 做日志复核别只信控制台控制台的Sampled requests只能看抽样时间粒度也短。要看完整流量特征最稳的方式是把WAF日志送到S3然后用Athena做SQL查询。WAF日志可以同时发送到CloudWatch Logs和S3。我习惯直接送S3因为Athena离线分析更灵活还不占CloudWatch费用。日志表建好后可以按来源IP、UA、命中规则做聚合分析。参考查询SELECT httprequest.clientip, COUNT(*) AS total_requests, COUNT(*) FILTER (WHERE action BLOCK) AS blocked_requests FROM waf_logs WHERE timestamp date_add(day, -7, now()) GROUP BY 1 ORDER BY blocked_requests DESC LIMIT 20;字段名可能因为建表方式略有差异以你实际表结构为准。通过这个查询可以快速识别出哪些IP在持续触发WAF规则以及哪些扫描行为没有命中任何规则成为下一轮规则迭代的素材。5. 误伤在线上的真实事件排查方法与策略进化任何WAF规则上线后都会遇到误伤区别只是早晚和严重程度。我这边经历过几次具代表性的误伤事件写出来给大家参考。5.1 手机 App 客户端批量被拦规则B的路径正则上线后很快发现有用户反馈App内部分页面打不开。排查发现手机原生App的请求路径里有backup关键词而App请求本身不含浏览器特征正好全部命中组合条件。这个误伤的根因在于我把命中可疑路径和非白名单IP组合在一起但没有排除业务内的合法客户端。解决方法是把App的健康检查接口、业务接口路径从正则集合里去掉同时为App服务端出口IP单独建一个IP Set放行。5.2 办公网出口 IP 触发速率规则速率规则刚开始设置的阈值偏低结果某天一整个部门的外网出口IP被限了。现象是办公网同事访问后台时间歇性出现403过几分钟又自己恢复。原因是整个部门共用少数几个弹性IP所有正常办公请求加起来在5分钟内达到了我在速率规则里设的数量。这个事件之后我把速率规则的ScopeDownStatement收得更紧同时把办公网出口IP加入白名单IP Set。这里有个实际操作心得白名单IP Set的更新要配合自动化否则办公网出口IP一变就得手工改WAF运维压力太大。5.3 把日志分析做成常态化规则要跟着流量迭代WAF规则的维护不是一次性的。扫描器会变ffuf的下游攻击者也会根据WAF的拦截结果调整行为。我现在每周会跑一次Athena分析重点看三个指标被Count的请求里路径和UA的分布有没有新聚集被Block的请求里来源IP的集中度有没有大量请求命中了ScopeDown但未到Block阈值这些量级是不是在持续上涨。如果发现某种新UA或新路径模式开始聚集我就把对应特征固化成新规则。WAF本质上是一套持续运营的策略系统靠的是对流量特征的敏感度而不是装完就忘。最后说两个我实际操作中最容易被忽略的细节。第一个是Web ACL的默认动作最好保持在Allow把拦截逻辑全部放进规则里这样灰度时即使规则写错也只影响部分请求不至于整体断站。第二个是WAF日志能开就开且尽量送到S3控制台的Sampled requests数据太有限真出了问题没有完整日志根本复盘不了。把日志留住了后面无论做误伤排查还是规则迭代你都会有据可查。