安全加固:从裸奔到还算扎实

举报
哦啦啦啦啦 发表于 2026/09/08 12:34:43 2026/09/08
【摘要】 昨天写完 thinrelay,功能跑通了就推上 GitCode。今天回头一看,安全方面基本是裸奔状态——网关用纯 HTTP 监听 0.0.0.0,API Key 明文比较,请求体无大小限制,上游错误直接透传给客户端……能用,但经不起推敲。于是做了一轮完整的安全审查,逐文件过了一遍代码,按严重程度分了三档,然后一次性全修了。 审查过程逐个文件读,重点关注几个方向:认证、网络传输、输入校验、错误...

昨天写完 thinrelay,功能跑通了就推上 GitCode。今天回头一看,安全方面基本是裸奔状态——网关用纯 HTTP 监听 0.0.0.0,API Key 明文比较,请求体无大小限制,上游错误直接透传给客户端……能用,但经不起推敲。

于是做了一轮完整的安全审查,逐文件过了一遍代码,按严重程度分了三档,然后一次性全修了。

审查过程

逐个文件读,重点关注几个方向:认证、网络传输、输入校验、错误处理、信息泄露、资源耗尽。

读完之后整理出 15 个问题,分三档:

  • 严重(2 条):会被直接利用,不修会出事
  • 中等(9 条):安全反模式,不会直接被打穿但留了口子
  • 轻量级(4 条):锦上添花,不紧急但应该做

修了什么

严重

1. 网关没有 TLS。 代码里用的是 ListenAndServe(),纯 HTTP。但配置监听的是 8443 端口,README 里客户端连的也是 https://。实际上 API Key、OAuth token、对话内容全部明文在网络上跑,任何中间人都能抓。

修法:加了 TLSConfig 结构体,配置了 cert/key 就走 ListenAndServeTLS(),没配置就打 warn 日志提醒用反代。同时把默认监听地址从 0.0.0.0:8443 改成 127.0.0.1:8443,需要外部访问时用 Caddy/Nginx 反代。

2. 请求体无大小限制。 io.ReadAll(r.Body) 没有上限,一个 2GB 的 body 就能 OOM。

修法:加了 bodyLimitMiddleware,用 http.MaxBytesReader 限制 10MB。peekModel 里也改用 io.LimitReader

中等

3. API Key 非常量时间比较。 != 做字符串比较会在第一个不匹配字节短路返回,理论上可以通过时序攻击逐字节猜出 key。

修法:改用 crypto/subtle.ConstantTimeCompare

4. Codex/OpenRouter 上游无超时。 用的是 http.DefaultClient,没有 timeout。上游卡住会永远挂着连接。

修法:创建 upstreamClient,设 5 分钟超时。Codex 和 OpenRouter 都改用这个 client。

5. 错误响应泄露上游内部信息。 AGY 上游返回非 200 时,把完整响应体返回给了客户端,可能暴露 Google 内部 API 结构。

修法:对外只返回 upstream error (status),详细信息写日志。

6. Codex/OpenRouter 无限速。 限速只加在 AGY 上,Codex 和 OpenRouter 完全没有。API Key 泄露后可以无限刷配额。

修法:加了全局限速 200 RPM,叠在 auth 后面。

7. copyHeaders 透传所有上游头。 只跳了 Transfer-EncodingConnection,其他全透传,可能泄露 Set-CookieServer 等内部头。

修法:改白名单,只透传 Content-TypeContent-LengthCache-ControlX-RateLimit-*

8. 默认监听 0.0.0.0。 有公网 IP 的 VPS 上任何人都能访问。

修法:默认改 127.0.0.1:8443

9. keyring 读取有命令注入风险。 fmt.SprintfKeyringService 直接拼进 Python 代码字符串,如果值包含恶意字符可以执行任意命令。

修法:python3 改用 sys.argv 传参,不拼接字符串。

轻量级

10. 无优雅退出。 SIGTERM/SIGINT 直接杀进程,在途请求会丢。

修法:signal.Notify + server.Shutdown(),10 秒优雅退出窗口。

11. 日志无客户端 IP。 出问题没法追踪来源。

修法:logMiddleware 加 "client", r.RemoteAddr

12. /healthz 不需认证。 暴露服务器存在性。

修法:只允许 127.0.0.1 / ::1 访问,外部请求返回 404。

13. Token 缓存 50 分钟。 Token 撤销后网关会继续用旧 token 50 分钟。

修法:缩短到 15 分钟(Codex 和 AGY 都改了)。

14. 配置明文存密钥。 config.yaml 里 API Key 是明文。

修法:支持环境变量 THINRELAY_API_KEY / THINRELAY_OPENROUTER_API_KEY 覆盖,从文件读取时打 warn 日志提醒。

15. /v1/models 硬编码。 返回的模型列表写死在代码里。

修法:改为从配置 models 字段读取,留空则用默认列表。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。