Skip to content

fix(openai): /openai/responses/stream 加每用户限流(INV-006) - #41

Merged
longsizhuo merged 1 commit into
mainfrom
fix/openai-stream-rate-limit
Jul 18, 2026
Merged

fix(openai): /openai/responses/stream 加每用户限流(INV-006)#41
longsizhuo merged 1 commit into
mainfrom
fix/openai-stream-rate-limit

Conversation

@longsizhuo

Copy link
Copy Markdown
Member

Closes InvolutionHell/involutionhell#297

漏洞

/openai/responses/stream 烧付费 LLM 额度,但只有 @SaCheckLogin 没有任何限流:登录用户可绕过 Next.js 层的 Upstash 限流直接 curl 后端刷额度(Caddy 裸 reverse_proxy 透传不过滤路径)。#297 里已确认当前线上 key 是过期的 Intern-S1 key、暂不失血,但换真 key 的那天洞就复活——限流必须落在 Java 层本身。

修复

  • OpenAiStreamRateLimiter:Caffeine(已有依赖)每用户固定窗口计数,默认 10 次/分钟OPENAI_STREAM_RPM env 可调),超限抛 429。进程内存级即可——后端单实例部署;将来横向扩容换 Redis 计数,接口不变。窗口边界突发(瞬时最多 2N)对防刷额度场景无关紧要,不为此上滑动窗口
  • 控制器在进入流式处理前 rateLimiter.checkOrThrow(StpUtil.getLoginIdAsLong())
  • SECURITY.md 新增 INV-006「付费 LLM 端点必须每用户限流」,按仓库不变量纪律配 3 个回归测试:超限 429 / 用户间隔离 / 窗口过期后恢复(可注入假 Ticker 驱动时钟)

验证

  • ./mvnw test 全量 246 个测试通过(含 SecurityInvariantsTests 全部既有不变量)
  • 过程中测试套件抓到一个真问题并已修:双构造器(生产 @value + 测试 Ticker)导致 Spring 无法选择注入入口、context 起不来——生产构造器已标 @Autowired

🤖 Generated with Claude Code

https://claude.ai/code/session_01USN2Liwrjd9TKVFJo5Za51

该端点烧付费 LLM 额度,此前只有 @SaCheckLogin 无限流——登录用户可绕过
Next.js 层的 Upstash 限流直接 curl 后端刷额度(Caddy 裸透传不过滤路径)。

- 新增 OpenAiStreamRateLimiter:Caffeine 每用户固定窗口计数,默认
  10 次/分钟(OPENAI_STREAM_RPM 可配),超限 429。进程内存级即可
  (单实例部署;横向扩容时换 Redis 计数,接口不变)
- 控制器在流式处理前 checkOrThrow(StpUtil.getLoginIdAsLong())
- SECURITY.md 新增 INV-006「付费 LLM 端点必须每用户限流」+ 3 个回归
  测试(超限 429 / 用户隔离 / 窗口过期恢复,假 Ticker 驱动)

全量 246 测试通过。
Copilot AI review requested due to automatic review settings July 18, 2026 19:33

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@longsizhuo
longsizhuo merged commit ede6dfc into main Jul 18, 2026
longsizhuo added a commit that referenced this pull request Jul 19, 2026
xhigh review (PR #43) 的已确认问题:
- init.sql 补 user_identities 表:三处 schema 同步惯例(INV-004 教训),
  否则 docker-compose 起的库缺表,M1 登录 500
- ADR 的 state 不变量 INV-006 → INV-007:INV-006 已被 PR #41 限流占用
- 回填注释澄清边界:依赖 SPRING_SQL_INIT_MODE=always;只治行缺失不治值变化;
  M2 解绑 github 须同时清 github_id 列,否则重启静默复活已撤销绑定
- 仓库层 provider 归一化小写:JustAuth source 名大写,不归一化查询侧静默查空
- insert() javadoc 声明忽略 linkedAt/lastLoginAt(由 DB default 生成)
- 幂等测试改从 classpath 的 schema.sql 机械提取回填语句,不再手抄副本

全量 252 测试通过。
longsizhuo added a commit that referenced this pull request Jul 19, 2026
* feat(usercenter): M0 多 provider 身份表 user_identities + 幂等回填

RFC involutionhell-backend#42 / ADR-001 的第一阶段,纯增量零行为变化:
- user_identities 表:UNIQUE(provider,provider_user_id) + UNIQUE(user_id,provider)
  + provider 小写 CHECK + FK ON DELETE CASCADE
- 启动回填存量 github_id → provider='github' 行,ON CONFLICT DO NOTHING 保幂等
- UserIdentity model + JdbcUserIdentityRepository(沿用 JDBC 惯例)
- 5 个仓库测试覆盖两条 UNIQUE、级联删除、回填幂等
- ADR-001(OKF frontmatter)记录设计决策与 OAuth state 防护协议

生产数据干跑验证:51 个 github_id 账号,0 重复 / 0 非数字 cast,回填无冲突。
全量 251 测试通过。

* fix(usercenter): 处理 M0 review 反馈

xhigh review (PR #43) 的已确认问题:
- init.sql 补 user_identities 表:三处 schema 同步惯例(INV-004 教训),
  否则 docker-compose 起的库缺表,M1 登录 500
- ADR 的 state 不变量 INV-006 → INV-007:INV-006 已被 PR #41 限流占用
- 回填注释澄清边界:依赖 SPRING_SQL_INIT_MODE=always;只治行缺失不治值变化;
  M2 解绑 github 须同时清 github_id 列,否则重启静默复活已撤销绑定
- 仓库层 provider 归一化小写:JustAuth source 名大写,不归一化查询侧静默查空
- insert() javadoc 声明忽略 linkedAt/lastLoginAt(由 DB default 生成)
- 幂等测试改从 classpath 的 schema.sql 机械提取回填语句,不再手抄副本

全量 252 测试通过。

* fix(db): 保证全新贡献者能干净启动——init.sql 补齐 user_accounts 列 + 去掉 never 建议

M0 的 user_identities 回填读 user_accounts.github_id,但 docker/init-db/init.sql
建的 user_accounts 只有 7 列、缺 github_id/avatar_url/email/preferences,schema.sql
的 CREATE TABLE IF NOT EXISTS 又补不上已存在表的列——全新 docker 卷首启时回填
直接 column "github_id" does not exist 崩,后端起不来(既有 bug:github 登录 INSERT
本就缺列,M0 把它升级成硬崩)。

- init.sql 的 user_accounts 补齐到与 schema.sql 一致
- .env.example / application.properties 去掉"改成 never"的误导建议:schema.sql
  幂等,always 是安全默认;改 never 会让后续新增表在本地缺失(曾踩坑)
- README 加建表两路径说明 + 缺表/缺列排查(down -v 重建卷)

验证:一次性 throwaway 容器跑 init.sql→schema.sql 两遍 exit=0、无缺列崩溃、
user_identities 建成且幂等。全量 252 测试通过。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[security] Java /openai/responses/stream 绕过 Next.js 限流,登录用户可直烧 OpenAI 付费额度

2 participants