- ZeYang2026-07-3135668
一、事情经过
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:296用gin.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 二进制做了完整复现(本地弱密钥环境 + 对自己线上实例的只读验证),结果与受害日志逐条吻合:
- 同一 IP 连错 5 次 → 第 6 次 403 封禁(封禁机制本身有效)
- 每次换伪造的
X-Forwarded-For→ 连续十几次全部 401,永不封禁,字典命中后返回 200- 用爆出的密钥
PUT /v0/management/api-keys写入新 key → 服务端日志打出api-keys count: 1 -> 2,新 key 立即可用- 固定伪造同一个假 IP 连试 → 401×5 后 403,证明封禁计数器确实是按(可伪造的)IP 算的
本文仅用于入侵复盘与防御提醒,复现均在本人环境及本人服务器上进行,请勿将所述方法用于未授权目标
五、上游修了吗?没有
我对比了 v7.2.100 到最新 v7.2.111 的全部 80 个提交:管理鉴权逻辑没有任何变化 GitHub 上有两个相关的 open PR(#3150 添加 trusted proxies 配置、#3160 加固代理认证),都没合并,也没有任何安全公告
也就是说:当前所有版本都存在这个问题,唯一有效的防线就是管理密钥本身的强度——只要你的管理面暴露公网、密钥又在常见字典里,被爆破只是时间问题
六、教训与加固清单
这次被黑的根因是三个问题叠加:管理面直接暴露公网、密钥强度不够,在攻击者字典里、防爆破机制被伪造请求头一招废掉
如果你也在用 CPA,也可以检查一下:
- 轮换一切:管理密钥换成 ≥24 位随机串;删掉不认识的 api-key;config 里所有上游 key、OAuth 凭据全部视为已泄露,全部轮换
- 关掉远程管理:不需要就置空
secret-key,整个 Management API 直接禁用- 反代层收口:Nginx 务必覆盖客户端传来的
X-Forwarded-For(proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;),并对/v0/management/加 IP 白名单或直接 deny- 服务别直接暴露公网,只经反代暴露必要端口
- 看日志:搜
/v0/management/的访问记录,出现陌生 IP 的 200 就是出事信号最后在想要不要给攻击者服务器上点压力呢 ^-^(bushi
主楼 - UEFI2026-07-317461
- 13:47:另一个 IP(155.117.84.62 香港 Lshiy 机房)打开管理面板
/management.html,并拉走了/v0/management/config、/auth-files、/openai-compatibility等接口 —— 配置里所有上游凭据全部泄露怎么感觉这个时候直接调用上游更加不知不觉呢,为什么还要调用 CPA,搞不懂
- ZeYang2026-07-3135668
可能为了防止上游做了平台风控(陌生IP之类的),直接用我的接口反而没有风险(认识我的IP) ^-^
- haojie7762026-07-3133207
可能是ai调的?给ai指令是“破解并使用他的cpa”类似的目标,但攻击者其实没有看过这个过程 ^-^
- 李寻欢2026-07-3117625
我的能被公网访问到的服务的key或者注册的某些网站的密码全都是一个随机生成的32位字符串。这都能被暴力破解只能说那是我欠他的。
- UEFI2026-07-317461
- ZeYang2026-07-3135668
emnn… 感觉主要还是我的密码太弱 ^-^(当时随手一填
- UEFI2026-07-317461
^-^ 给你推荐个好东西

1password.com

安全、强大的密码生成器 | 1Password
使用 1Password 强密码生成器为您的各个账户创建唯一密码。通过安全密码阻止黑客入侵并防范网络钓鱼攻击。
- Lexpl0it2026-07-3110632
原来的密钥太弱了,估计攻击者是全网扫cpa 然后挨个爆破的
- 盖世英雄卢本伟2026-07-3123680
你这个被入侵和CPA有什么太大关联,难道不是你弱密码造成的吗 ^-^
- 祖龙2026-07-3112546
给攻击的IP机房发 abuse 滥用报告
- ZeYang2026-07-3135668
不全部是 这既是配置问题(弱密钥、暴露管理面),也是应用层漏洞(安全决策基于未验证的客户端输入,gin 默认信任所有代理头)
- swd2026-07-3119306
吓得我也去查下cpa服务器,求个简单点的解法啊?
- XXL2026-07-3110690
佬,精彩的分析和复盘。建议先提给CPA官方修复后再公开哇
- 小黄2026-07-3111231
- bittersweet_21232026-07-319407
X-Forwarded-For 的问题可以在 Cloudflare 上配置 “从请求中删除HTTP标头”,这样就能看到真实IP
我上周也被攻击了,但是访问全都401了,密码强度够
我现在的服务只监听本地端口,然后走 Cloudflare 的 Tunnels 访问
- XTer2026-07-3120204
先叠甲:我没举报
因为肉眼可见的AIGC啊
也就是说:当前所有版本都存在这个问题,唯一有效的防线就是管理密钥本身的强度——只要你的管理面暴露公网、密钥又在常见字典里,被爆破只是时间问题
- 攻击者不是绕过,而是试出了正确的管理密钥
- jkcqw2026-07-3113270
管理面板直接暴露公网确实危险,我自用的 sub2api 都是只绑内网 + 反代加鉴权,不敢裸露。gin 那个默认信任代理头的坑我也踩过,后面都手动关了。佬这波损失多少额度啊^-^

