API 遭恶意扫描?教你用 Cloudflare WAF 规则精准拦截
最近搭建了个服务,日志里全是莫名其妙的 404 和探测请求,一看账单/API 调用次数差点心梗。这类恶意扫描和批量探测是每个站长的噩梦,特别是如果你挂了 OpenAI 的中转接口或者昂贵的 API 服务,被别人“白嫖”简直防不胜防。
既然域名都接在 Cloudflare (CF) 下了,为什么不让它来帮我们挡子弹呢?其实根本不需要复杂的后端代码,直接在 CF 控制台配置一条 WAF 规则就能解决问题。今天就分享一个简单粗暴但极其有效的防护方案——只允许带指定密钥的请求访问你的敏感接口。
为什么要在网关层拦截?
很多人习惯在应用层(比如 Nginx 或代码里)做鉴权,但这意味着流量已经打到了你的源站。虽然能拦截,但还是会消耗服务器资源。而 Cloudflare 作为反向代理和 CDN,可以在请求到达源站之前就将其阻断。这不仅能保护源站安全,还能节省带宽和计算资源。
核心思路:Header 校验
Cloudflare WAF 表达式编辑器,用于输入拦截规则
我们要实现的逻辑很简单:当请求访问特定的 API 路径时,检查 HTTP Header 里是否包含我们预先设定的 Authorization 密钥。如果没带,或者带错了,直接在 CF 层返回拦截页面,根本不给源站处理的机会。
手把手配置教程
请求被规则拦截后的 403 提示页面
第一步:进入 WAF 安全规则编辑页
登录 Cloudflare 控制台,选择你的域名,点击左侧菜单的 Security (安全) -> WAF。在“Custom rules (自定义规则)”选项卡下,点击 Create rule (创建规则)。
第二步:填写规则基本信息
- Rule name (规则名称): 随便起个你认识的,比如
Block_API_Without_Key。 - Field (字段): 选择
Expression Builder或者直接切换到Edit expression模式,这对于粘贴复杂表达式更方便。
第三步:输入核心拦截表达式
将以下代码粘贴到你刚才创建规则的表达式输入框中,并根据注释修改为你自己的域名和密钥:
http.host contains "你的域名.com"
and (
http.request.full_uri contains "/v1/responses"
or http.request.full_uri contains "/v1/chat/completions"
or http.request.full_uri contains "/v1/models"
)
and not any(http.request.headers["authorization"][*] contains "你的_API_密钥")
表达式详细解析:
-
http.host contains "你的域名.com"- 含义:限定这条规则只针对特定域名生效。
- 作用:防止你账号下其他网站误伤。
-
`http.request.full_uri contains "..."
- 含义:检查请求的完整路径是否包含关键字。这里列举了 OpenAI 接口常见的三个路径:
/v1/responses(通常用于某些对话模型)、/v1/chat/completions(最常用的对话接口)、/v1/models(模型列表,这通常是扫描器最先探测的地方)。 - 扩展:如果你有其他敏感路径(比如
/v1/audio/speech),直接用or拼接在后面即可。
- 含义:检查请求的完整路径是否包含关键字。这里列举了 OpenAI 接口常见的三个路径:
-
not any(http.request.headers["authorization"][*] contains "你的_API_密钥")- 含义:这是核心拦截逻辑。意思是:在请求头
authorization的所有值中,不包含你的指定密钥。 - 注意:这里使用的是
contains。如果你的客户端发送的是标准的 Bearer Token 格式(例如Bearer sk-xxxx),确保你的密钥字符串能被contains命中(比如只填sk-xxxx这种核心部分即可)。
- 含义:这是核心拦截逻辑。意思是:在请求头
第四步:设置动作和部署
- Action (操作): 选择 Block (拦截)。
- 其余设置: 保持默认即可。
- 点击 Deploy (部署) 大功告成。
效果验证
配置完成后,你可以用 curl 或者 PostMan 测试一下:
-
不带密钥请求:
curl -H "Content-Type: application/json" https://你的域名/v1/models预期结果:直接返回 Cloudflare 的 403 拦截页面,源站日志里不会留下任何记录。
-
带正确密钥请求:
curl -H "Content-Type: application/json" -H "Authorization: Bearer 你的_API_密钥" https://你的域名/v1/models预期结果:正常访问源站,返回接口数据。
避坑指南与进阶建议
-
密钥安全:在写规则时,虽然密钥是展示在 CF 界面上的,但尽量不要使用你根账号的超级密钥,建议单独为代理服务生成一个受限的 API Key,并定期轮换。
-
关于 URI 包含匹配:目前的规则
contains比较宽泛,如果你有其他接口路径里刚好包含/v1/chat/completions字样但不属于敏感接口,可能会被误伤。不过大多数情况下,精准匹配http.request.uri.path更好,如果路径带参数比较复杂,可以使用full_uri。 -
Rate Limiting (速率限制):除了做鉴权,建议顺便在 CF 的 Rate Limiting 里给这个接口加个限流。比如同一 IP 每分钟只能请求 30 次,防止就算对方拿到了密钥,因为程序 Bug 或者恶意刷请求导致你的额度耗尽。
总结一下,通过这一层简单的 WAF 规则,我们成功把绝大多数的脚本小子和无脑扫描挡在了门外。不需要改一行代码,安全等级直接上一个台阶,这种免费又高效的羊毛,赶紧薅起来!

评论已关闭