Buzeli
buzeliSoluções Digitais
安全

媒体上传被 403 拦截:没人记录的 AWS WAF 8 KB 限制

发布于 2026年7月19日

Um upload de arquivo sendo barrado por uma parede de WAF com um limitador de tamanho de 8KB

症状:只在上传时 403,且只在超过某个大小时

一个 WordPress 站点的编辑报告上传图片出错——但只有部分。小文件能过;大一些的就 403。公开站点正常。查看 WAF 日志,被拦的请求很清楚:

复制
action=BLOCK  uri=/wp-admin/async-upload.php  method=POST
terminatingRule=AWS-AWSManagedRulesCommonRuleSet  ruleId=SizeRestrictions_BODY
bodySize=85701

原因:SizeRestrictions_BODY 与 8 KB 检查上限

SizeRestrictions_BODY 托管规则(来自 AWS 的 Common Rule Set)会拦截大的请求体。但有个微妙处:WAF 只检查请求体的前 8 KB(更高档位为 16 KB)。一个 84 KB 的上传同时撞破规则上限和检查上限——在到达 WordPress 之前就被拦下。

Common Rule Set 默认很好用,直到这条大小规则把合法的图片上传当成攻击。任何接收上传的应用,都需要为其上传路由设一个有意识的例外。

修复需要一个标签匹配——而且顺序要对

出路不是禁用规则(会丢失防护)。而是把它置于 COUNT 模式以发出一个 label,然后创建你自己的、优先级更低的规则,当 label 存在且路径是上传时放行该请求。如果托管规则仍处于 BLOCK,它会在你的规则运行之前就拦截——这正是 COUNT 必不可少的原因。

CloudFront WAF 的坑:没有 RegexMatchStatement

要匹配路径 /wp-admin/async-upload.php,本能是用正则。但关联到 CloudFront 分发的 WAF(CLOUDFRONT/全局作用域)不支持 RegexMatchStatement。你必须用 ByteMatchStatement 配 ENDS_WITH/STARTS_WITH。而通过 --cli-input-json 提交时,SearchString 用 base64:

复制
{
  "Name": "allow-wp-upload",
  "Priority": 0,
  "Action": { "Allow": {} },
  "Statement": {
    "ByteMatchStatement": {
      "SearchString": "L3dwLWFkbWluL2FzeW5jLXVwbG9hZC5waHA=",
      "FieldToMatch": { "UriPath": {} },
      "PositionalConstraint": "ENDS_WITH",
      "TextTransformations": [{ "Priority": 0, "Type": "NONE" }]
    }
  },
  "VisibilityConfig": { "SampledRequestsEnabled": true,
    "CloudWatchMetricsEnabled": true, "MetricName": "AllowWpUpload" }
}

耗费时间的细节:Description 字段的最小长度为 1(空字符串会校验失败),并且只有当发出 label 的托管规则处于 COUNT(而非 BLOCK)时,label 才生效。Pro 功能(override、label、SizeConstraint、对 Cookie 的 ByteMatch)在 Free 套餐里不存在。

经验教训

1. SizeRestrictions_BODY 默认拦截大上传。每条上传路由都需要例外;WAF 只检查请求体的前 8 KB。

2. 托管规则必须置于 COUNT,label 才生效。处于 BLOCK 时,它会在你的放行规则之前结束评估。

3. CloudFront WAF 没有 RegexMatchStatement。用 ByteMatch(ENDS_WITH/STARTS_WITH);通过 CLI/JSON 时,SearchString 是 base64。

结论

Common Rule Set 默认防护得很好——默认也把你编辑的图片上传当成可疑载荷。这个 403 既不是攻击,也不是 WordPress 的 bug:是大小规则在不知上下文的情况下尽职。一个顺序正确的 label 匹配,配上 ByteMatch(因为 CloudFront 不接受正则),在不降低防护的前提下把上传还了回来。