Files
yanweidong 63aeedc2fe docs: add per-module audit reports (18 modules)
Add static security/quality audit reports for all 18 Go service modules under module/, plus a consolidated index (docs/audit/README.md) with per-module statistics, top risks, cross-module systemic defects and a phased TODO list (T1-T19). No production code is modified.
2026-09-14 22:16:27 +08:00
..

module/ 全模块审计索引

状态:生成中(各模块审计文件完成后由主流程回填统计表与汇总 TODO

审计范围

  • 审计对象:module/ 下全部 18 个含 go.mod 的独立服务模块go.work 成员)。
  • 每个模块由独立审计 agent 完成,产出 docs/audit/module-<路径>.md
  • 未纳入审计(无 Go 代码,不属于运行时服务):
    • module/ec/supply:仅 1 个 README.md,无 go.mod
    • module/finance/bill:空目录。
    • module/finance/loan:空目录。

审计维度

安全(鉴权/越权/注入/密钥/隐私)、正确性(错误处理/事务/并发/状态机/精度、性能N+1/索引/分页/缓存)、可维护性(重复/分层/TODO/空实现)、健壮性与可观测性(超时/重试/迁移耦合/日志/配置)、测试覆盖。

问题级别定义

级别 含义
P0 可被利用的安全漏洞 / 必然导致数据损坏或资金损失
P1 高概率线上故障、越权、性能瓶颈
P2 可维护性、健壮性、可观测性缺陷
P3 风格、文档、一致性改进

模块审计文件

模块 审计文件 P0 P1 P2 P3 合计
base/ads module-base-ads.md 0 3 11 7 21
base/cloud module-base-cloud.md 5 15 14 5 39
base/cms module-base-cms.md 1 11 16 5 33
base/feedback module-base-feedback.md 3 8 15 2 28
base/fts module-base-fts.md 2 5 10 7 24
base/initial module-base-initial.md 0 8 6 8 22
base/logs module-base-logs.md 2 13 6 5 26
base/mgt module-base-mgt.md 2 9 15 4 30
base/passport module-base-passport.md 8 7 6 4 25
base/sender module-base-sender.md 4 12 12 6 34
ec/address module-ec-address.md 2 7 6 4 19
ec/mall module-ec-mall.md 5 13 19 8 45
ec/market module-ec-market.md 2 8 9 5 24
ec/order module-ec-order.md 7 12 10 5 34
finance/wallet module-finance-wallet.md 5 11 8 6 30
social/feed module-social-feed.md 3 13 14 7 37
social/group module-social-group.md 0 13 12 6 31
social/relation module-social-relation.md 1 15 14 4 34
合计 18 个模块 52 183 205 102 542

计数说明:base/cloud 的 P0 为 agent 原始上报,主流程复核后认为其中 P0-1/P0-2/P0-3 应下调(见下「主流程复核记录」);social/feed 经 agent 自查将 JWT 密钥一项由 P0 下调为 P1理由生产是否注入 BSM_JwtSecretKey 无法从仓库确认)。按上述修正,全仓 P0 = 4852 3 1其余级别不变。 base/mgt 计数以报告第 6 节为准P0=2/P1=9/P2=15/P3=4报告正文编号 131其中 P2-17 为主流程通知后修正机制的一项。

各模块最高风险速览

模块 最高风险(摘要,详见各模块报告)
base/passport Forget.Reset 无鉴权改他人密码并写裸 MD5登录/注册接口不校验 codeJWT 密钥缺省为公开常量 Cblocksmesh2022C → 零成本接管任意账号
base/sender 短信/邮件接口无鉴权、日限额计数器只有读没有写、验证码可无限爆破 → 短信轰炸/费用损失/账号接管
ec/order 订单/购物车/优惠券定位与写入信任客户端入参且无归属校验 → 读他人收货信息、任意订单置为已支付、核销任意券;confirm.go 必然 panic
finance/wallet 支付回调不入账 + Payment.Callback 由客户端决定"支付成功" + 支付宝渠道 Body 未初始化必然 panic
ec/mall 仓库内公开的 32 字节占位 JWT 密钥可直接用于签发 HS256 token叠加"角色/店铺归属全采信 claims、写操作无租户隔离" → 接管任意店铺
base/mgt root 默认口令 123456 自动播种 + JWT 密钥默认值 + 50 个管理接口仅粗粒度 RequireAdmin → 接管最高权限
base/cloud 照片表无 passport_id、照片接口靠 album_id 反查(已复核为非越权);分享口令明文存储与比较、加解密密钥完全由客户端决定
social/feed 动态写操作无属主校验 + 可见性控制被默认值击穿 → 读写删全站动态
social/relation 命名返回指针未初始化必然 panic无 recover→ 远程打挂进程;好友/关注/标签列名系统性错配 → 静默假成功
base/logs IP 校验逻辑反向 + X-Forwarded-For 可伪造 + 路由全匿名 → 伪造审计日志、读取全量日志
base/cms 写接口仅校验"任意有效 JWT"无归属校验;Site 5 个接口空实现却返回成功
ec/address Get/Modify/Deleteowner_identity 校验 → 枚举读改删全站收货人 PIIFetch 裸 return 恒返回 nil
base/feedback Get/Delete/Remark 无鉴权无归属校验;Modify 覆盖 identity → 工单失联、子表脱钩
base/fts 客户端可控 bucket 直接拼入落盘路径 → .. 穿越任意目录写MinIO 分支可写任意桶
base/initial Config 把可控 os 拼进 ORDER BY → SQL 注入6 个字典接口无鉴权无限流
base/ads 独立入口网关整体 404唯一接口无鉴权无限流且 pos_key 无索引全表扫描
social/group 13 个 RPC 中 12 个确定性缺陷(表名/列名错、结果被丢弃、权限与 SQL 全错);Disband 是返回 OK 的模板 TODO
ec/market 管理接口只验签名不验角色/归属 → 自审通过、删他人代理商、拉全量身份证;代理商登录签发的 token 不是 JWT

汇总 TODO跨模块优先事项

按"先止血、再治本"排序。每条对应各模块报告中的具体 TODO 项,验收标准见对应文件。

阶段一P0 止血(上线前必须完成)

  • T1 统一密钥治理|动作:Authorization.Key、SDK JWT_SECRET_KEY、各模块 SecretKey 全部改为强制注入且启动期校验(拒绝 CHANGE_ME*Cblocksmesh2022C4ef05311358cd1c8f787281f08b38b1c 等任何仓库内出现过的值;长度校验之外增加熵/黑白名单校验)|验收:以仓库内任意历史占位符启动必须失败|涉及:pkgs/all/etc/default_dev.yaml:22pkgs/ecmall/etc/default_dev.yaml:22、SDK crypto/token/jwt.go:34module/base/mgt/internal/logic/pub/login.go:90module/ec/mall/internal/config/config.go:41
  • T2 账号接管链路封堵|动作:Forget.Reset 接入真实验证码校验与身份校验;Login.Code/QuickRegister.Code 真正校验 code;删除 MD5 写入路径;为 passport_accountaccount/phone 唯一索引|验收:无 code 无法登录、无法改他人密码、库中不再产生 MD5 口令|涉及:module/base/passport/internal/logic/forget/reset.go:31login/code.go:17login/quick.go:20register/code.go:13internal/logic/common/token.go
  • T3 资金与交易完整性|动作:支付回调真正入账并加签名验签与幂等;Payment.Callback 禁止客户端置状态;AliPay.Body/ctx 初始化;订单/优惠券/购物车全部补服务端归属校验;confirm.go panic 修复并加 recovery 拦截器|验收:伪造回调不能改状态、并发下单不超卖、越权订单操作返回 403涉及module/finance/wallet/internal/logic/payment/callback.go:25alipay/alipay.go:15,53module/ec/order/internal/logic/**
  • T4 越权与无鉴权接口收敛|动作:按各模块报告清单补齐 ParseMetaCtx + 归属过滤 + 角色校验;独立入口禁止裸奔(补鉴权或直接不暴露)|验收:以 A 账号 token 访问 B 账号资源全部 403/404涉及base/feedbackmethod/get.go:19)、base/logsrouters/register.go:23 注释掉的 JwtAuthec/addresslibrary/get.go:29)、ec/marketagency/approve.go:15)、ec/mallbase/cmssocial/feedbase/senderbase/initial
  • T5 远程 panic / DoS 修复|动作:修所有 nil 解引用与无保护类型断言,并为全部 gRPC server 装配 recovery 拦截器|验收:go test -run 与手工用例下不再 panic进程不退出涉及social/relationfriend/tag_fetch.go:22friend/apply_get.go:32)、finance/walletalipay.go:53)、ec/orderconfirm.go:62)、base/logslog/fetch.go:29,45)、ec/addresslibrary/fetch.go:16-40
  • T6 上传路径穿越|动作:对 bucket/文件名做白名单与 filepath.Clean + 前缀校验或改用服务端映射表MinIO 桶名同样校验|验收:bucket=../../x%2e%2e%2f 均被拒|涉及:module/base/fts/internal/logic/handler.go:27provider.go:26,99
  • T7 SQL 注入点修复|动作:Configos 改为参数化或白名单枚举排序|验收:注入 payload 不再进入 SQL涉及module/base/initial/internal/logic/check/config_cache.go:21

阶段二P1 治本

  • T8 修复 S-1 网关模板缺陷|动作:internal/server/new.go 初始化 gwRuntime.NewServeMux() 并注册 handlercmd/main 改用 service.Expose;或明确关闭 Gateway.Enable 并同步文档|验收:独立二进制下文档中的 REST 路由可达|涉及:全部 18 个模块的 internal/server/new.goservice/expose.gocmd/main/main.go
  • T9 修复 S-3 token 签发不一致|动作:ec/marketec/mall 的登录改用与聚合网关一致的 HS256 JWT 签发验收B 端登录 token 可通过 pkgs/ecmall 网关校验|涉及:module/ec/market/internal/logic/agency/login.go:53module/ec/mall/internal/logic/staff/login.go:88
  • T10 数据完整性|动作:补事务包围多表写入、去掉 Select()+Updates(结构体) 的零值覆盖、修正被改写的主键、补唯一索引与幂等|验收:并发与重复提交下无脏数据|涉及:base/mgtuser/modify.go:64permission/modify.go:140)、base/feedbackmethod/modify.go:37,89)、ec/orderbase/cloudalbum/delete_album.go:45-54)、ec/address(默认地址)
  • T11 明文凭据与 PII 治理|动作:轮换仓库/etc/.builds 中出现的所有口令与密钥PII 加密存储 + 日志脱敏 + 关闭生产 gorm Debug验收仓库与构建产物中扫描不到真实凭据日志无明文 PII涉及module/base/feedback/etc/feedback_prod.yaml:4.builds/etc/feedback_prod.yaml:4scripts/build-all-linux.sh:100module/base/cloud(分享口令)、module/finance/wallet(银行卡/身份证)、module/ec/market(证件资料)
  • T12 未实现接口显式化|动作:所有模板桩与空实现改为返回 codes.Unimplemented 或补齐实现,禁止"假成功"|验收:调用未实现接口返回明确错误而非 OK涉及base/cmssite/*)、social/groupDisband)、ec/marketdata/*)、base/senderTencentSender)、finance/wallet(转账/放款)
  • T13 限流与审计日志|动作:登录/短信/上传/写接口加限流;管理端高危操作留审计痕迹;短信/邮件日限额计数器落写入侧|验收:超阈值请求被限流并有记录|涉及:base/senderbase/mgtbase/logs
  • T14 启动与迁移解耦|动作:拆分连接/迁移/seed关闭生产 AutoMigrateDebug,补真实迁移脚本(仓库当前无 .sql)|验收:只读实例与蓝绿发布可用|涉及:全模块 internal/implinternal/models

阶段三P2/P3 收尾

  • T15 可观测性与优雅退出|补 /health、结构化日志、context.WithTimeout、可用的大盘指标;修 defer srv.Stop() 因 SDK select{} 永不执行的问题|涉及:全模块 cmd/main
  • T16 测试补齐|优先覆盖认证、权限、越权、订单状态机、并发扣款/核销、优惠券、崩溃路径;修复当前失败/失效的既有测试(如 module/base/fts/internal/routers/register_test.go 路由断言 FAIL、.http 服务名大小写错误)|涉及:各模块 test/
  • T17 清理死代码与失效文档|移除零引用包(如 base/fts/internal/{response,errors}、各模块 cmd/cli Hello World、grpcConnsMemorySerice 等),修正 README/wiki 与实现不符的描述(缓存策略、/health、Makefile、Dockerfile 等)|涉及:全仓
  • T18 配置一致性proddev 配置不得字节级相同;修正 Service: 名与模块不符(如 ec/address 的 etc 写 Service: order);统一命名与拼写(MemorySerice)|涉及:各模块 etc/*.yaml
  • T19 补充 scope 说明module/ec/supply(仅 READMEmodule/finance/billmodule/finance/loan(空目录)、social/relation/service(空目录、缺 expose.go)需明确归属或补齐|验收:目录不再有"空壳"歧义

主流程复核记录

审计 agent 的结论并非全部可信,主流程对高危结论逐一回读源码复核,修正如下(未单独说明的 P0 均已被源码证据直接证实):

模块 agent 结论 复核结果
base/passport Forget.Reset 无鉴权改他人密码并写裸 MD5三个验证码登录接口不校验 code 成立internal/logic/forget/reset.go:18-31(仅校验非空后按 identity 直改 password,且写入 utils.Md5internal/logic/login/code.go:17-21(只判空即签发 token
base/initial Config 接口把调用方可控 os 拼进 ORDER BY 成立internal/logic/check/config_cache.go:21 字符串拼接进 Order()GORM 无法参数化该位置
base/mgt 初始化种子内置 root/123456 成立internal/models/init_db.go:15-16:145 仅打印"请尽快修改默认密码"
social/relation TagFetch 命名返回指针未初始化导致必然 panic 成立internal/logic/friend/tag_fetch.go:15,22 对未初始化的 *pb.FriendTagsReply 直接 Count(&reply.Total),且 internal/server/new.go:23grpc.NewServer() 无 recover 拦截器 → 可远程打挂进程。同源问题见 ec/address/library/fetch.go:16-40(裸 return 恒返回 nil
base/feedback Get/Delete/Remark 无鉴权无归属校验Modify 覆盖 identity 成立internal/logic/method/get.go:19-29 全文无 ParseMetaCtx,查询仅 Where("identity = ?")internal/logic/method/modify.go:37 写入新 utils.UUID()Identity:89Updates(record) → 业务主键被改写、子表 item_identity 脱钩
base/cms 写接口仅校验"任意有效 JWT",无归属校验 成立internal/logic/post/delete.go:29 显式传空 author 过滤并留 // Todo:internal/logic/site/create.go:20-27 为模板桩却返回 vars.OK(假成功)
social/feed 动态写操作无属主校验 成立internal/logic/post/remove.go:17-25ParseMetaCtx 后即 models.DeletePost(in.Identity),无属主过滤;delete_comment.go:17-24 同构
social/group Disband 为返回 OK 的模板 TODOModify 会随机重写群 identity 成立internal/logic/basic/disband.go:26// TODO: add your logic code 且函数返回成功;internal/logic/basic/modify.go:33 写入随机 utils.UUID()Identity:35UpdateColumns(record) 全列写入(含 identity 与零值 PassportID/MemberTotal
ec/mall 公开占位 JWT 密钥可直接签发 HS256 token 成立pkgs/all/etc/default_dev.yaml:22pkgs/ecmall/etc/default_dev.yaml:22CHANGE_ME_32_BYTE_JWT_SECRET_KEY 恰为 32 字节,通过 SDK crypto/token/jwt.go:34-36 的长度校验,并被 pkgs/all/internal/server/authorization.go:39,78 直接用作 HS256 签名密钥 → 可离线伪造管理员 token两个聚合入口均受影响
base/cloud P0-1/2/3照片无 passport_id 导致跨用户照片读写删与相册级联删除越权 高估,需下调internal/models/cloud_photo.go 确实没有 passport_id,但照片级接口通过 JOIN cloud_albums ... WHERE cloud_albums.passport_id = ? 强制归属校验(album/delete_photo.go:31-32album/get_photo.go:31album/update_photo.go:32album/list_photos.go:36,44album/set_cover_photo.go:32 校验相册归属、:39 校验照片属于该相册;album/delete_album.go:31passport_id 限定待删相册。不构成越权。其中两个子问题独立成立并保留:delete_album.go:45-54 两次删除无事务(非原子),以及 CloudPhotopassport_id 属反规范化脆弱设计(可降级为 P1/P2

跨模块系统性缺陷(主流程独立确认)

以下问题不是单个模块的偶发缺陷,而是模板/生成器级别的共性,建议在汇总层单独立项修复,而不是在 18 个模块里各修一遍。

S-1P0所有模块的独立部署入口没有可用的 HTTP 网关

证据链(主流程已逐个核对):

  1. internal/server/new.go 声明了 Mux *gwRuntime.ServeMux 字段(如 module/base/sender/internal/server/new.go:16),但 New() 只注册 gRPC server:33-34从不调用 gwRuntime.NewServeMux()Mux 恒为 nil;全仓库 gwRuntime.NewServeMux() 仅出现在 pkgs/all/internal/server/server.go:38pkgs/ecmall/internal/server/server.go:38
  2. 每个 service/expose.gooptions.Gateway 直接传给生成的 pb.Register*HandlerServer(如 module/base/sender/service/expose.go:30,33)。
  3. 生成的注册函数对 nil mux 无任何防御,第一行即 mux.Handle(...)(如 module/base/sender/pb/sms.pb.gw.go:97-98)→ 传入 nil 立即 panic。
  4. 独立部署的 cmd/main/main.go 只调用 server.New(nil) 并自行 net.Listen从不调用 service.Expose,因此独立二进制下网关要么整体 404、要么在接入 Expose 时启动即 panic。

影响:adsinitialaddresscmscloudftS 等多个模块的审计都独立报告了「独立部署 HTTP 网关 404 / Mux 为 nil」根因是同一处模板缺陷。README 宣称的独立部署 REST 入口在该形态下不可用。

S-2P1infra.Response 为包级单例且被并发写

bsm-sdk/core/infra/response.goResponse 是包级变量、方法直接改字段,ftslogs 两个模块均独立报告了并发响应串包/数据竞争风险。属 SDK 级缺陷,需在 SDK 侧改为每次请求新建响应对象或加锁。

S-3P0两套不兼容的 token 签发方式B 端登录 token 被聚合网关拒绝

聚合入口的鉴权中间件只接受 HS256 JWTpkgs/all/internal/server/authorization.go:73-79pkgs/ecmall/internal/server/authorization.go:73-79 使用 jwt.ParseWithClaims 并强制 WithValidMethods(["HS256"])

而各模块签发 token 的路径分成两类:

模块 位置 实际产物 与聚合网关兼容
passport登录/注册全部 4 处) internal/logic/common/token.go:10token.New(...).GenerateJwt(...) 真正 JWT函数名有误导性
mgt internal/logic/pub/login.go:90refresh.go:28GenerateJwt 真正 JWT
ec/market internal/logic/agency/login.go:53encipher.GenerateTokenAes AES-CBC + base64不是 JWT
ec/mall internal/logic/staff/login.go:88encipher.GenerateTokenAes AES-CBC + base64不是 JWT

证据:bsm-sdk/core/crypto/encipher/encipher.goGenerateTokenAes 最终调用 AesEncryptCBC + base64.StdEncoding,输出形状为密文 base64无法被 jwt.ParseWithClaims 解析。

影响market 代理商与 mall 员工登录成功后拿到的 token 无法通过聚合入口网关校验B 端登录链路在该拓扑下不可用P0 可用性问题,非安全漏洞)。market 的审计已独立发现该点P0-2mall 的审计需一并核对。

汇总 TODO

(待回填)