最近搭建了个服务,日志里全是莫名其妙的 404 和探测请求,一看账单/API 调用次数差点心梗。这类恶意扫描和批量探测是每个站长的噩梦,特别是如果你挂了 OpenAI 的中转接口或者昂贵的 API 服务,被别人“白嫖”简直防不胜防。

既然域名都接在 Cloudflare (CF) 下了,为什么不让它来帮我们挡子弹呢?其实根本不需要复杂的后端代码,直接在 CF 控制台配置一条 WAF 规则就能解决问题。今天就分享一个简单粗暴但极其有效的防护方案——只允许带指定密钥的请求访问你的敏感接口。

为什么要在网关层拦截?

很多人习惯在应用层(比如 Nginx 或代码里)做鉴权,但这意味着流量已经打到了你的源站。虽然能拦截,但还是会消耗服务器资源。而 Cloudflare 作为反向代理和 CDN,可以在请求到达源站之前就将其阻断。这不仅能保护源站安全,还能节省带宽和计算资源。

核心思路:Header 校验

WAF 表达式配置示例

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_密钥")

表达式详细解析:

  1. http.host contains "你的域名.com"

    • 含义:限定这条规则只针对特定域名生效。
    • 作用:防止你账号下其他网站误伤。
  2. `http.request.full_uri contains "..."

    • 含义:检查请求的完整路径是否包含关键字。这里列举了 OpenAI 接口常见的三个路径:/v1/responses(通常用于某些对话模型)、/v1/chat/completions(最常用的对话接口)、/v1/models(模型列表,这通常是扫描器最先探测的地方)。
    • 扩展:如果你有其他敏感路径(比如 /v1/audio/speech),直接用 or 拼接在后面即可。
  3. 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
    

    预期结果:正常访问源站,返回接口数据。

避坑指南与进阶建议

  1. 密钥安全:在写规则时,虽然密钥是展示在 CF 界面上的,但尽量不要使用你根账号的超级密钥,建议单独为代理服务生成一个受限的 API Key,并定期轮换。

  2. 关于 URI 包含匹配:目前的规则 contains 比较宽泛,如果你有其他接口路径里刚好包含 /v1/chat/completions 字样但不属于敏感接口,可能会被误伤。不过大多数情况下,精准匹配 http.request.uri.path 更好,如果路径带参数比较复杂,可以使用 full_uri

  3. Rate Limiting (速率限制):除了做鉴权,建议顺便在 CF 的 Rate Limiting 里给这个接口加个限流。比如同一 IP 每分钟只能请求 30 次,防止就算对方拿到了密钥,因为程序 Bug 或者恶意刷请求导致你的额度耗尽。

总结一下,通过这一层简单的 WAF 规则,我们成功把绝大多数的脚本小子和无脑扫描挡在了门外。不需要改一行代码,安全等级直接上一个台阶,这种免费又高效的羊毛,赶紧薅起来!

标签: none

AI Skills Smart Station on Nick Launches

评论已关闭