我的 API 中转站被爆破了:【CLIProxyAPI 】管理接口入侵复盘

ZeYang 2026-07-31 15:13 1

一、事情经过


7 月 30 日,我部署在 api.***.cloud 上的 CPA(CLIProxyAPI v7.2.100)出现异常调用 查日志后发现:有人通过管理接口给自己签发了一把 API key,然后用我的上游额度白嫖模型调用


攻击时间线非常清晰:




  • 12:29:57 – 12:31:02:来自全球几十个不同 IP 的请求密集访问 GET /v0/management/api-keys,全部返回 401,每次耗时 58–61ms;此后爆破全天不断(14:48、深夜均有波次,一直持续到次日凌晨 01:44,全天共 249 次尝试)




  • 13:18:54:一个新 IP(103.151.173.208 日本IKUUU VPN 出口)第一次请求就返回 200




  • 13:18:55:同一 IP 发起 PUT /v0/management/api-keys,日志打出 api-keys count: 1 -> 2——攻击者的 key 被写进了我的配置文件




  • 13:47:另一个 IP(155.117.84.62 香港 Lshiy 机房)打开管理面板 /management.html,并拉走了 /v0/management/config/auth-files/openai-compatibility 等接口——配置里所有上游凭据全部泄露




  • 13:58 起:155.117.84.61–64 开始用注入的 key 调用 /v1/responses/v1/messages(零星几次,试探性质)




  • 17:26 – 次日 08:21:第三个 IP(107.173.42.94 美国 RackNerd 代理型 IP)接管盗用,彻夜不间断调用 /v1/messages/v1/responses、Gemini 接口共 3748 次——这段时间我几乎没用服务,全是攻击者在烧我的额度











    Cloudflare 后台也印证了这波爆破:/v0/management/api-keys 以 252 次登顶 4xx 路径榜,攻击时段源站错误明显飙升




二、第一反应:是不是鉴权被绕过了?


管理接口的鉴权代码(internal/api/handlers/management/handler.go:265-397)看起来挺结实:




  • 密钥用 bcrypt 校验,常量时间比较,没有硬编码后门;




  • 连续失败 5 次,封 IP 30 分钟(handler.go:341-355



    但有个细节出卖了一切:攻击成功那次请求也花了 59ms——这正是 bcrypt 运算的耗时 如果是绕过,不会走 bcrypt 结论:攻击者不是绕过,而是试出了正确的管理密钥




那问题来了:5 次失败就封 IP,他是怎么试出来的?


三、真正的漏洞:封禁机制基于一个可以随便伪造的 IP


问题出在 IP 的取法上 代码用 gin 框架的 c.ClientIP() 取客户端 IP(handler.go:272),而 gin 默认信任所有代理头——项目的 internal/api/server.go:296gin.New() 创建引擎后,从未调用 SetTrustedProxies 收紧这个行为



这意味着:任何人只要在请求里加一个 X-Forwarded-For: 随便什么IP,服务器就把这个假 IP 当成客户端 IP。封禁计数器是按这个假 IP 算的,每换一个假 IP 就是一个"新用户",封禁永远不触发


日志里那波"来自全球几十个国家、一次一个、间隔 1–3 秒"的请求,根本不是什么僵尸网络——一台机器轮换请求头就能演出来


更糟的是,连 allow-remote: false(仅允许本机管理)这个开关也看同一个 IP(handler.go:337):伪造 X-Forwarded-For: 127.0.0.1 就直接被当成 localhost,形同虚设


四、复现验证


我用 v7.2.100 官方 release 二进制做了完整复现(本地弱密钥环境 + 对自己线上实例的只读验证),结果与受害日志逐条吻合:




  1. 同一 IP 连错 5 次 → 第 6 次 403 封禁(封禁机制本身有效)




  2. 每次换伪造的 X-Forwarded-For → 连续十几次全部 401,永不封禁,字典命中后返回 200




  3. 用爆出的密钥 PUT /v0/management/api-keys 写入新 key → 服务端日志打出 api-keys count: 1 -> 2,新 key 立即可用




  4. 固定伪造同一个假 IP 连试 → 401×5 后 403,证明封禁计数器确实是按(可伪造的)IP 算的





本文仅用于入侵复盘与防御提醒,复现均在本人环境及本人服务器上进行,请勿将所述方法用于未授权目标



五、上游修了吗?没有


我对比了 v7.2.100 到最新 v7.2.111 的全部 80 个提交:管理鉴权逻辑没有任何变化 GitHub 上有两个相关的 open PR(#3150 添加 trusted proxies 配置、#3160 加固代理认证),都没合并,也没有任何安全公告


也就是说:当前所有版本都存在这个问题,唯一有效的防线就是管理密钥本身的强度——只要你的管理面暴露公网、密钥又在常见字典里,被爆破只是时间问题


六、教训与加固清单


这次被黑的根因是三个问题叠加:管理面直接暴露公网、密钥强度不够,在攻击者字典里、防爆破机制被伪造请求头一招废掉


如果你也在用 CPA,也可以检查一下:




  1. 轮换一切:管理密钥换成 ≥24 位随机串;删掉不认识的 api-key;config 里所有上游 key、OAuth 凭据全部视为已泄露,全部轮换




  2. 关掉远程管理:不需要就置空 secret-key,整个 Management API 直接禁用




  3. 反代层收口:Nginx 务必覆盖客户端传来的 X-Forwarded-Forproxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;),并对 /v0/management/ 加 IP 白名单或直接 deny




  4. 服务别直接暴露公网,只经反代暴露必要端口




  5. 看日志:搜 /v0/management/ 的访问记录,出现陌生 IP 的 200 就是出事信号




最后在想要不要给攻击者服务器上点压力呢 ^-^(bushi

最新回复 (17)
  • UEFI 07-31 15:20
    1


    • 13:47:另一个 IP(155.117.84.62 香港 Lshiy 机房)打开管理面板 /management.html,并拉走了 /v0/management/config/auth-files/openai-compatibility 等接口 —— 配置里所有上游凭据全部泄露



    怎么感觉这个时候直接调用上游更加不知不觉呢,为什么还要调用 CPA,搞不懂

  • ZeYang 楼主 07-31 15:39
    2

    可能为了防止上游做了平台风控(陌生IP之类的),直接用我的接口反而没有风险(认识我的IP) ^-^

  • haojie776 07-31 15:39
    3

    可能是ai调的?给ai指令是“破解并使用他的cpa”类似的目标,但攻击者其实没有看过这个过程 ^-^

  • 李寻欢 07-31 15:47
    4

    我的能被公网访问到的服务的key或者注册的某些网站的密码全都是一个随机生成的32位字符串。这都能被暴力破解只能说那是我欠他的。

  • UEFI 07-31 15:54
    5

    X-Forwarded-For 这个的话,你套一层 CDN 应该就可以解决了,CDN 默认会把真实 IP 放进去的,伪造的一般不会算数


    然后应该也不算 BUG 吧,感觉更多的是配置不当

  • ZeYang 楼主 07-31 16:06
    6

    emnn… 感觉主要还是我的密码太弱 ^-^(当时随手一填

  • UEFI 07-31 16:12
    7

    ^-^ 给你推荐个好东西


  • Lexpl0it 07-31 16:14
    8

    原来的密钥太弱了,估计攻击者是全网扫cpa 然后挨个爆破的

  • 盖世英雄卢本伟 07-31 16:20
    9

    你这个被入侵和CPA有什么太大关联,难道不是你弱密码造成的吗 ^-^

  • 祖龙 07-31 16:27
    10

    给攻击的IP机房发 abuse 滥用报告

  • ZeYang 楼主 07-31 16:28
    11

    不全部是 这既是配置问题(弱密钥、暴露管理面),也是应用层漏洞(安全决策基于未验证的客户端输入,gin 默认信任所有代理头)

  • swd 07-31 16:30
    12

    吓得我也去查下cpa服务器,求个简单点的解法啊?

  • xxl 07-31 16:31
    13

    佬,精彩的分析和复盘。建议先提给CPA官方修复后再公开哇

  • 小黄 07-31 16:31
    14


    奇怪了,这帖子为什么会被举报啊?不是很正常的分析吗?


    我发现我的Caddy配置是安全的,会转发真实的IP,至于密码,爆破不出来的,我何止24位

  • bittersweet_2123 07-31 16:32
    15

    X-Forwarded-For 的问题可以在 Cloudflare 上配置 “从请求中删除HTTP标头”,这样就能看到真实IP


    我上周也被攻击了,但是访问全都401了,密码强度够


    我现在的服务只监听本地端口,然后走 Cloudflare 的 Tunnels 访问

  • XTer 07-31 16:33
    16

    先叠甲:我没举报


    因为肉眼可见的AIGC啊



    也就是说:当前所有版本都存在这个问题,唯一有效的防线就是管理密钥本身的强度——只要你的管理面暴露公网、密钥又在常见字典里,被爆破只是时间问题





    • 攻击者不是绕过,而是试出了正确的管理密钥


  • jkcqw 07-31 16:38
    17

    管理面板直接暴露公网确实危险,我自用的 sub2api 都是只绑内网 + 反代加鉴权,不敢裸露。gin 那个默认信任代理头的坑我也踩过,后面都手动关了。佬这波损失多少额度啊^-^

* 帖子来源Linux.do
返回