## 背景 PR #295 给 Next.js 的 \`/api/chat\` 和 \`/api/suggestions\` 加了 Upstash per-IP rate-limit。但**登录用户可以绕过整个 Next.js 层**,直接 curl 后端: \`\`\`bash curl -X POST https://<backend-host>/openai/responses/stream \\ -H "satoken: <user-token>" \\ -H "Content-Type: application/json" \\ -d '{...}' \`\`\` - 命中的是 \`OpenAiStreamController.streamResponses\`,有 \`@SaCheckLogin\` 但**没有任何 rate-limit** - Java 那边烧的是 \`OPENAI_API_KEY\`(**付费**),不是前端的 GLM 免费额度 - Caddy 是裸 \`reverse_proxy\` 透传,不过滤路径也不限流 ## 影响 - 风险级别:**中**(要先登录+知道 URL+主动绕,门槛不低) - 潜在损失:如果一个恶意用户循环调用 10 tokens 的 prompt × 10 次/秒,每小时烧 ~$5 OpenAI 额度 ## 修复路径(三选一,按难度) ### A. Java 层加分布式 rate-limit(推荐) - 在 \`OpenAiStreamController\` 前加 Spring Interceptor / AOP - 用和 Next.js 同一个 Upstash Redis 实例,共享额度桶(key = userId,不是 IP) - 每用户 **20 req/min** 就够拦住滥用,正常用户完全感知不到 ### B. Caddy 层 per-IP rate-limit - Caddy 原生支持 \`rate_limit\` 插件 - 比 A 粗糙:打在 IP 级别,同 NAT 多用户会被误伤 - 优点:零代码,改 Caddyfile 就行 ### C. Next.js ↔ Java 共享密钥,Java 只认内网请求 - Next.js 代理时带一个 \`X-Internal-Token\` header - Java 的 \`/openai/responses/stream\` 加 Interceptor 校验该 header - 外部直连全部 403 - 最彻底,但需要前后端两边改 ## 建议 先做 A。@Crokily 你看呢?Issue 先挂着,等这波 PR 全合完再排日程。 Refs: #295 #296
Activity
longsizhuo commentedon Apr 16, 2026
更新:后端现状摸清 + 风险重新评估
登录服务器直接查了运行中的后端容器,拿到真实情况:
```
OPENAI_API_KEY = <过期的 Intern-S1 key> ← 不是真 OpenAI key
OPENAI_API_URL = https://api.openai.com/v1 ← 但 URL 指的是真 OpenAI
OPENAI_MODEL = gpt-4.1
```
结论:Java 这条路径当前完全没跑通。每次请求 → OpenAI 返 401 → Java 抛错 → Next.js fallback 到本地 GLM。登录用户和匿名用户的 AI 回答都来自 Next.js 的 GLM。
这意味着:
处理方案(按 @longsizhuo 决策)
Java 路径保留作为 fallback,但底层也走 GLM(免费 ≈ 无烧钱风险):
.env.example和docker-compose.yml默认值 OpenAI → GLMOPENAI_*,Java 代码走 OpenAI-compatible 协议不动一行本 Issue 状态
降级为"跟踪项"。当且仅当未来真激活 OpenAI 付费时才需要做 Java 层的 per-user rate-limit(方案 A)。到时再 reopen 或新开 issue 跟进。
建议:本 issue 等 backend PR #8 合并后关闭。
longsizhuo commentedon Jul 18, 2026
修复 PR 已开:InvolutionHell/involutionhell-backend#41 —— Java 层每用户限流(Caffeine 固定窗口,默认 10 次/分钟,
OPENAI_STREAM_RPM可调),超限 429;SECURITY.md 立了 INV-006 不变量 + 3 个回归测试防回归。merge 后本 issue 自动关闭。