Files
tamabox/.workbuddy/memory/2026-09-11.md
T

43 lines
3.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 2026-09-11 工作日志
## 代码审阅(全库,安全/正确性/可优化)
结论:**无 P0、无 P1 可利用漏洞**;仅 P2(一致性 / 健壮性 / 性能)。
### 已验证「没问题」的项(勿重复排查)
1. **越权**:所有写接口均有归属校验 —— `getOwnedVote` 显式比对 `vote.UserID != ctx.User.ID`(vote.go:388-401);
question 路由挂在 `question.Questioner` 中间件组(route.go:262-274),`PublishAnswer` 二次校验 `question.UserID`;
follow-up 写操作以 `question.ID` 为作用域(`AnswerByID`/`UpdateAnswerByID`)。profile/password/harassment/tags/features 一律用 `ctx.User.ID`。
2. **SQL 注入**:`internal/db` 全部用 `?` 绑定参数;拼接仅出现在常量/配置(dedupeUniqueFields、tagCond、randomFunc)。
3. **XSS**:`internal/template/markdown.go` 白名单消毒扎实 —— strip `on*`、禁 `style`、`safeURL` 协议白名单
(http/https/mailto/相对)、拒 `//` 协议相对、强制 `rel="noopener noreferrer"`。
4. **竞态**:follow-up 用事务 + `FOR UPDATE` 行锁;投票「一人一票」用复合唯一索引。
5. **GORM bool 默认值陷阱**:已规避(`Enabled` 不加 `gorm:"default:true"`,见 feature_control.go:79-81),
且 `reconcileLegacyChatEnabled`(:609-618)修复旧 backfill 脏行。
6. **审核缓存回放无 fail-open**:`AliyunTextCensorParser`(aliyun.go:433-461)与 `QiniuTextCensorParser`
(qiniu.go:133-170)都会从 raw 重建 `Details`,故 `Decide` 仍能按当前档位裁决(改档位对历史缓存同样生效)。
⚠️ text.go:66 注释称「回放缓存结果时为 nil」**是错的**,需修正。
### P2 清单(待用户选批后落地)
| # | 文件:行 | 问题 | 建议 |
|---|---|---|---|
| 1 | censor.go:72,111,118-125 | 缓存按**原文** `text` 查,实际送审 `RemoveTrustedURL(text)`,落库 `Input` 存原文 → 审计与实际送审不一致 + 归一化相同文本重复调 API | 归一化一次,查找/送审/落库统一用归一化文本,原文另存字段 |
| 2 | censor.go:85-102 | qiniu 缓存命中仅 `Pass` 才返回,aliyun 命中即返回(不看 Pass)→ 依赖「aliyun 恒为链尾」隐式前提 | 两分支语义对齐,或显式固化链尾不变量 |
| 3 | text.go:66 | 注释失真(称回放时 Details 为 nil,实际会重建) | 修正注释 |
| 4 | route/vote/vote.go:814-822 | 配额用「插入后计数」判定,非原子条件插入 → 并发可短暂超额(有界、自动结束自愈) | 改 `WHERE count<quota` 条件插入或 DB 计数列 |
| 5 | route/user/profile.go:194-215 | Name/Intro/各 link 无长度校验直传 `db.Users.Update` | 补 rune 长度校验(对齐 vote/block-word) |
| 6 | internal/db/users.go:89 | `User.Email` 带 `json:"email"`(对比 Password/BlockWords 为 `json:"-"`)→ 潜在 PII 泄露 | 改 `json:"-"` |
| 7 | internal/db/db.go:215-222 | 用 `conf.Database.Schema` 拼 `CREATE SEQUENCE`(配置来源,纵深防御) | 校验/白名单 schema 标识符 |
| 8 | text.go:114-141 | `RemoveTrustedURL` 对 12 host × 2 protocol = 24 次整串重建 | 单次正则/一次遍历 |
另:`question.go:214` 提问人 token 在 URL 中(邮件链接),**设计如此**,会出现在邮件日志/Referer,可接受。
### 编译状态(延续 09-10)
- 重包 `./route/user/ ./internal/route/ ./internal/db/` 再次 **30 分钟超时(exit 124,无报错)**
→ 判定为 1C1G 沙箱编译整图慢,**非代码错误**(注释改动不影响编译,20 文件 `gofmt -e` 均可解析)。
- 已确认可编译:GROUP1(security/censor、conf、form、template、shared、captcha)EXIT=0;`./internal/db/` EXIT=0。
- 温缓存重试(task zGnX3L)仍在跑,25 分钟上限。