Files
full/wiki/audit-2026-09-22-总体审计报告.md
2026-09-22 21:15:34 +08:00

24 KiB
Raw Permalink Blame History

总体审计报告2026-09-22

本报告是产品级汇总,汇总逐微服务审计结论。逐服务明细见 docs/21 篇)。

一、审计范围与方法

内容
审计对象 BSM Infra Full 后端 Go workspacego 1.27.1
覆盖模块 module/ 18 个业务服务 + pkgs/allpkgs/ecmall 2 个聚合入口 + scripts 与工作区配置
代码量 module/ 903 个 .go177 个 .http、66 个 .proto、58 个 .yaml)、pkgs/ 54 个 .go
方法 只读静态分析:逐文件读 cmd/ internal/ service/ proto/ etc/,生成代码 pb/ 仅看接口签名
输出 每服务一份 docs/<服务名>.md;本文与《产品与服务目录》为产品级汇总

审计约定:结论均带 文件:行号;无法确认处以【信息不足】标注;修复建议只给最小、直接动作,不含过度设计/过度封装方案

二、结论摘要

架构组织清晰(服务域划分、service.Expose 注入、聚合入口只做注册表取舍),但实现质量与完整性存在系统性缺口:本仓库当前状态更接近"可编译的接口骨架",而非可上线的生产系统。

  • 认证与鉴权:至少 5 个模块的验证码校验形同虚设passport、mall多处接口只校验"是否登录"而不校验"是否有权操作该资源"address、cms、group、relation、feed、mall、market、feedback、order
  • 资金链路wallet 支付回调不验签、提现不扣减、余额扣减读后写order 模拟支付/发货生产可达且优惠券计算写反,存在直接资金损失路径
  • 数据正确性:多处引用模型中不存在的列名(relation_id/creator_id/createor_id/enabled 等)与错误键名,导致接口恒失败或静默返回空;
  • 上线阻断聚合入口无生产配置、JWT/session 密钥默认值可直接启动、首批部署不建表不播种、scripts/api-docgen 无法构建;
  • 测试:全仓仅 21 个 *_test.gobase 多数模块、wallet、social 三服务零单测,上述缺陷几乎无自动化拦截。

三、严重问题台账

P0 · 严重(认证绕过 / 资金损失 / 数据越权 / 上线即故障)

编号 服务 问题 证据 影响
S1 passport 验证码登录/快捷登录/注册/找回均不校验验证码 login/code.go:16-59login/quick.go:20-64register/code.goforget/verify.go 任意手机号 + 任意 code 登录/批量建号,账号体系失守
S2 passport 找回密码仅凭 identity 重置,且写未加盐 MD5 forget/reset.go:17-41,31 任意账号接管;重置后密码无法通过 bcrypt 登录
S3 mgt AppKey 登录明文相等比对密码列 pub/login.go:147-159 pass-the-hash哈希泄露即可登录
S4 mgt dev 配置注入默认管理员 root/123456 etc/mgt_dev.yaml:16internal/models/init_db.go:16 默认弱口令后台
S5 wallet 支付回调不验签,用调用方传入状态置成功 internal/logic/payment/callback.go:16-31 客户端自证支付成功;渠道回调 WxCallback 反为 // Todo 不落库(wechat/wx_callback.go:38
S6 wallet 提现只校验余额不扣减、无幂等键 internal/logic/basic/apply_cash.go:35-49 余额可重复开单超额提现;ChargeWallet 全仓无调用点→充值链路不通
S7 wallet 余额扣减为读后写、WHERE identity=? 无条件更新 internal/logic/basic/wallet.go:53-63 并发双花
S8 order 模拟支付/发货/收货生产可达且硬编码支付参数 logic/summary/simulate_pay.go:25proto/summary.proto 直接伪造支付并推进订单状态
S9 order OrderApprove 完全无鉴权 logic/mgt/order_approve.go:17 匿名审批退款并改写库存
S10 order 优惠券金额做加法加入订单总额 logic/summary/confirm.go:72 用户应付变高;归属/有效期/门槛不校验
S11 order 扣库存不检查 RowsAffected logic/summary/submit.go:209-217 超卖
S12 mall 员工验证码登录不校验验证码 internal/logic/staff/login.go:58 任意手机号接管店铺账号
S13 mall 店铺支付/邮件凭据任意登录用户可读改 logic/store/get_payment.goset_payment.goget_email.goset_email.goget_setting.go 渠道凭据外泄/被篡改
S14 market 审核无鉴权、开号/删号鉴权被整段注释 agency/approve.go:15-46agency/create.go:20-23agency/delete.go:17-21 自助开号 + 自助审核 + 匿名封停他人
S15 market 登录令牌用 AES-CBC、鉴权用 HS256 JWT互不兼容 agency/login.go:53 vs ParseMetaCtxSDK crypto/token/jwt.go:68 合法 token 过不了任何接口;解析失败后访问 nil Claims → panic 可打崩进程
S16 initial os 参数字符串拼进 ORDER BY check/config_cache.go:21 SQL 注入
S17 initial 版本判断用字符串不相等即"有更新" check/updates.go:39 客户端版本高于服务端记录时被强制降级
S18 group 入群审批无角色校验(丢弃调用者身份) member/join_do_handle.go:19,24-52 任意登录用户可拉人入群/拒绝申请
S19 group Modify 重写群 identityUpdateColumns 不过滤零值 basic/modify.go:33-35 群成员/申请立即脱钩,"群消失"
S20 relation 通过好友申请时不与申请记录比对 friend/apply_do_pass.go:24-47 单方面把任意陌生人加为好友
S21 cms 文章/评论 Delete/Modify 不校验归属 post/delete.go:29modify_comment.go:33delete_comment.go:24 任意登录用户删改他人内容
S22 address Get/Modify/Delete 无 owner 约束 library/get.go:19,29modify.go:39delete.go:19,24 遍历自增 id 获取他人姓名/手机号/详细住址并可改删
S23 cloud 空间 KeyIdentifier 全局唯一 + 写入字面量 "default" models/cloud_space.go:12space/get.go:29-50 首名用户之后所有人拿不到空间
S24 cloud 私人资料"加密"名不副实key 由客户端传入、服务端不加密) logic/private/encrypt_data.gocreate_private_data.go:54 服务端明文存"加密"数据
S25 ads / feedback / logs 三个模块业务接口全挂匿名组 logs/internal/routers/register.go:21-27adsfeedback 可伪造写入、全量读取
S26 logs fetch 键名不一致 + level 类型断言双 panic,分页参数失效,create IP 过滤写反 logic/log/fetch.go:42,45,33-53create.go:21 接口 500 / 全表返回 / 防护失效
S27 feed 动态越权删改 + 私密动态泄露 post/remove.go:25change.go:40models/query.go:30-37,60-71 删除他人动态;is_open=false 内容仍被返回
S28 pkgs/all · ecmall JWT 密钥默认值恰为 32 字节,直接通过长度校验 etc/default_dev.yaml:22internal/config/config.go:66-69 可自行签发任意身份 token
S29 pkgs/all · ecmall grpc-gateway 404 与业务 NotFound 无法区分 internal/server/server.go:63-71 所有"记录不存在"分支的真实响应被 Gin 纯文本 404 覆盖
S30 sender 腾讯云短信空实现 return nil,nil internal/logic/sms/send.go:151-153 接口返回 200 + null,调用方误判成功

P1 · 高

编号 服务 问题 证据
H1 sender 日发送量限制与短信黑名单从未生效(只有读、无写入点) sms/send.go:37,42-51
H2 sender 验证码 SetNX 忽略返回值却发码;Verify 成功不删码可重放;用 math/rand sms/send.go:62-65,81,169verify.go:28-32
H3 passport 密码哈希用 bcrypt.MinCostcost=4Token 缓存键 /TOKEN//token/ 不一致 register/do.go:30account/set_password.go:35vars/token.go:3 vs register/do.go:84
H4 cloud 容量配额只统计不限制;分享密码明文;CreateShare 不校验 resource_id 归属;根目录 *ParentID 空指针 panic space/*logic/share/*get_dir.go:91get_dir_tree.go:97
H5 cms 评论发布 authName["name"].(string) panic赞踩无去重可刷负Search 无分页上限 add_comment.go:35-40query.go:346incr_post_like.go:38
H6 address Fetch 命名返回值未赋值恒返回空;默认地址唯一性无事务保障 library/fetch.go:23-40create.go:41-45
H7 market Offset 在归一化前计算、Limit(0) 致待审核列表恒空;三处 Count 结果被丢弃 agency/fetch.go:19,27-32pending.go:31
H8 group creator_id/createor_id 列不存在→核心接口恒返回 ErrDB、免验证入群永久失效 modify.go:35do_quit.go:24do_set_manager.go:25models/query.go:39-43
H9 relation TagFetch 必然 panicFetch/ApplyFetch 返回 (nil,nil)7 个接口引用不存在的 relation_id 列;Undo/DoIgnore 无归属删除 tag_fetch.go:22friend/fetch.go:47-49delete.go:27 等、follow/undo.go:18,26match/do_ignore.go:19,27
H10 feed 分页写成 Limit(int(page)) 且未回写;DeleteComment 是空函数;action_op 误写 action_type models/query.go:67,122-125,50
H11 wallet 支付宝分支 AliPay.Body 为 nil 直接调用→必 panic改支付密码不校验旧密码微信 APIv3 密钥/商户号明文入库wallet_prod.yaml 字段名不匹配无法启动 alipay/alipay.go:46-53basic/set_pay_password.go:23-29etc/wallet_prod.yaml:56
H12 order 跨服务直连同库(mall_product/mall_product_spec/mall_store/address_library 8 个文件,散见 logic/summary/*
H13 mall 12 处写操作无店铺归属校验(商品/规格/图片/分类/广告/公告/运费/员工) product/item_modify.go:29spec_delete.go:28
H14 initial areas_cache.go 查询模型不存在的列且 DB 错误被覆盖→静默空列表并缓存 30 分钟 areas_cache.go:33-35
H15 pkgs/all · ecmall 无 prod 配置(BSM_RuntimeMode=prodlog.Fatalfbuild-all-linux.sh 不覆盖聚合入口 pkgs/all/etc/default_dev.yamlbuild-all-linux.sh:7,30
H16 pkgs/ecmall 聚合路径不建表不播种,Mgt.InitRootUser 在聚合下不生效 service/*.goNewImpl/AutoMigrate/models.New 调用
H17 mock/order OrderModify 占位但返回成功social 三服务未接入聚合且 Mux 恒为 nil order/logic/mgt/order_modify.gosocial/*/internal/server/new.go
H18 scripts scripts/api-docgen 当前无法构建,且与工作区依赖版本长期漂移 6 处 scripts/api-docgen/generate.sh:5-7;实测 GOWORK=off go build ./...updates to go.mod needed
H19 workspace go.work 与 20 处 go.mod 把 SDK 指向仓库外相对路径go.sum 无校验和 go.work:26、各 go.mod replace
H20 scripts verify-workspace.* 的 gofmt 门禁漏 scripts/、对空模块列表静默成功;缺 .gitattributes 致 CRLF 文件使门禁失败 verify-workspace.ps1/sh;实测 gofmt -lmodule/base/fts/internal/routers/register_test.go

P2 · 中

  • feedback / market / order / mall 等多处列表接口无分页上限(可全表扫描/拖库):feedback 各方法、mgt/internal/tool/tool.go:5-14mallcms 等。
  • 占位实现仍返回成功group Basic.Disbanddisband.go:26-31、order OrderModify、feed 4 类 Timeline + Tag.PostList + Post.CommentList + Setting.Info/Rights9 个占位 RPC、wallet 7 个占位 RPC、mall 入驻/授权/小程序码/运费、market Data 全 5 文件、cms Site 全系列、cloud 部分——统计见《产品与服务目录》。
  • 云解析/错误吞没passport account/get.go:44 未处理 errorrelation tag_member_fetchgroup createor_id .Scan 错误丢弃。
  • GORM 链式未回写 tx / First+Group 语义不确定logs、feedback 等。
  • 调试残留logs/routers/register.go:20 fmt.Println、feed 多处 fmt.Print
  • 鉴权口径不一致:模块 yaml 匿名白名单、聚合 Authorization.Anonymous 白名单与模块实际声明三者互不吻合ads/feedback/passport 均出现)。

P3 · 低

  • 死代码与未用初始化ads RedisService/MemorySerice 零引用logs RedisService/EtcdService 未用、Dependencies.Cache 未应用relation follow.Do 死代码。
  • internal/excode/ex.go 为空文件;多处 crate 级常量与配置注释不一致。
  • test/grpc/main.go 硬编码明文 JWT。

四、按服务域的问题分布

flowchart LR
    A["认证与账号<br/>passport · mgt · mall.staff"] --> A1["验证码不校验<br/>默认密码<br/>pass_hash"]
    B["资金与订单<br/>wallet · order"] --> B1["回调不验签<br/>提现不扣减<br/>优惠券算反<br/>超卖"]
    C["资源越权<br/>address · cms · group · relation · feed · mall · market · feedback"] --> C1["只校验登录<br/>不校验归属/角色"]
    D["聚合与上线<br/>pkgs/all · pkgs/ecmall · scripts"] --> D1["密钥默认值<br/>404 分流<br/>无 prod 配置<br/>docgen 不可构建"]

五、共性根因

  1. 鉴权只到"认证"不到"授权":大量写接口只判断调用者已登录,缺少"该资源是否属于调用者 / 调用者是否为管理员"的条件。越权类问题占本次 P0 的近一半,且分布在 9 个模块,属同一模式。
  2. 验证码体系形同虚设passport、mall 的登录/注册路径根本不调用验证码比对sender 的码生成(SetNX 忽略返回值)、校验(成功不删码)、限额(无写入点)三处同时失效。即使调用方正确接入,也无法形成有效校验
  3. 资金链路缺三要素:无验签、无事务、无幂等。walletorder 各自独立缺失,且模拟支付接口在生产可达。
  4. 配置与代码长期漂移yaml 字段名与 SrvConfig 不匹配wallet/feed 需 log.Fatalf/panic 才能启动)、匿名白名单三处口径不一致、占位实现返回成功、生产配置缺失。这些在"能编译/能 dev 跑"阶段不会暴露。
  5. 列名/键名错误被吞没:模型与实际表列不一致(relation_id/creator_id/createor_id/enabled/show_town/sort_order),叠加 .Scan 错误被丢弃、命名返回值 reply 未赋值,形成"接口 200 但返回空/报错被掩盖"的静默故障。
  6. 测试覆盖极低:全仓 21 个 *_test.go 集中在 fts/mgt/sender/mall/market/order/pkgsbase 多数模块、walletsocial 三服务零单测。上述缺陷几乎没有任何自动化拦截。

六、修复优先级路线(务实)

按"止血 → 阻断上线 → 修恒失败 → 补护栏"推进,全部为对现有函数/配置的最小改动:

  1. 资金与认证止血(最高优先)
    • wallet回调按渠道验签、金额与服务端记录核对、加幂等键提现改为事务内扣减/冻结;余额扣减改条件更新(WHERE balance >= ?)。
    • passport / mall登录、注册、找回路径补回验证码比对Forget.Reset 必须校验一次性令牌。
    • mgt移除默认管理员密码改必填环境变量AppKey 登录改为哈希比对。
    • orderSimulate*OrderApprove 加鉴权与生产开关(默认关闭);优惠券改为减法并校验归属/门槛/有效期;扣库存检查 RowsAffected
  2. 越权批量化修复
    • 统一给"按主键操作"的写接口补条件address/cms/group/relation/feed/mall/market/feedback 分别补 passport_id/owner/店铺归属/群管理员角色。
  3. 上线阻断项
    • pkgs修复 404 分流判定先读业务响应再回退JWT/session 密钥去除可用默认值;补 prod 配置;聚合路径补建表/播种。
    • scripts修复 api-docgen 构建、纳入工作区或固定版本、gofmt 门禁补齐SDK 改为可解析的版本依赖或明确文档化本地前提。
  4. 恒失败接口修复
    • 修正不存在的列名/键名group/relation/initial/feed/logs修复命名返回值 reply 未赋值address/relation补齐 main.go 的 HTTP Mux 与聚合注册social
  5. 补护栏
    • 优先为认证、权限、支付、订单状态机、库存、验证码写单测CI 增加 workspace 验证、凭据扫描、proto 一致性与依赖漏洞扫描。

七、正向结论

  • 密码哈希market、mall 的账号创建/登录/改密已从 MD5 加盐迁移到 bcrypt历史 MD5 需通过重置流程迁移)。
  • mgt 鉴权:管理路由已正确挂载 RequireAdminIsSuperAdmin(按 DB 回查超级管理员角色),模块内未见绕过;其短信重置密码实现正确校验 Redis 验证码,与 passport 形成对比。
  • cloud 数据隔离:所有 DB 查询均为 GORM 参数化(无 SQL 拼接/注入),接口以 passport_id = auth.ID 隔离,未发现跨用户越权读取他人目录/相册/笔记/书签/私人资料。
  • pkgs 动态 RPC:具备 4 MiB 请求体上限、头部白名单透传、方法描述符缓存;两个聚合入口有针对鉴权/动态 RPC/配置/路由的单元测试。
  • 2026-08-10 审计的整改:绝对路径 replace、样例固定 secret 已处理(本次替换为仓库外相对路径,可移植性问题转为 P1

八、与 2026-08-10 审计报告的关系

wiki/audit-2026-08-10.md 聚焦"workspace 结构、样例凭据、进程与端口防护",其列出的 P0/P1 多数已整改。本报告在其基础上下沉到业务实现层,发现的 P0 数量与严重度显著高于前次——原因是前次未逐接口审计业务逻辑。两份报告不冲突,应合并为同一整改清单跟踪。

九、整改结果2026-09-22

按第六节的优先级路线,已对全部 18 个业务服务 + 2 个聚合入口 + 工作区/工程脚本执行整改,覆盖各服务报告中标注为「高」的全部条目(132 项,含本报告 P0/P1 台账)。逐服务的「处理结果」见 docs/<服务名>.md 的「整改记录」章节。

整改原则

约束 执行情况
不做过度设计/过度封装 未引入新框架、抽象层、DTO/VO、事件总线、消息队列未拆分服务边界未引入 DDD/CQRS
加密统一 bcrypt 口令类摘要全部为 bcryptDefaultCostpassport、mgt、mall、market、wallet 支付密码、wallet 改密校验旧密码。验证码等短时效一次性凭证仍按原有 Redis 明文比对链路存储(用 bcrypt 会破坏跨模块链路)
注释中文化 新增/修改的注释、配置注释、脚本提示均为中文
契约冻结 未修改任何 proto/*.proto 与生成的 pb/*.go(本机无 protoc少量需新增字段才能完整实现的项目做了安全降级已在对应报告中标注

关键整改落点

结果
资金链路 wallet回调改渠道验签+金额核对+幂等、充值入账接通、余额与提现改条件更新+事务+流水、支付密码改 bcrypt 且须校验旧密码、渠道凭据不再明文入库、配置字段名修正。order模拟接口加 dev 开关与鉴权、OrderApprove 补鉴权与状态校验、优惠券改减法、扣库存原子更新防超卖、取消订单回补库存、store_id/单价取值修正、五类越权补归属校验
认证与会话 passport四条路径接入真实验证码校验、找回密码改一次性票据、Token 键前缀统一、密码哈希 bcrypt。mgtAppKey 登录改 bcrypt 比对、移除 root/123456 弱口令。mall员工验证码登录补校验
越权批量化 address、cms、group、relation、feed、mall、market、feedback 共 8 个模块按「主键操作必带归属条件」补齐;涉及改删他人地址/内容/动态/群成员、单方面加好友、无鉴权审核开号等
上线阻断 pkgs/all、pkgs/ecmall补 prod/test 配置、构建脚本覆盖聚合入口、拒绝公开默认 JWT/session 密钥、修复 gateway 404 与业务 NotFound 的分流;聚合启动补建表/播种。scriptsapi-docgen 恢复可构建并纳入门禁、依赖版本对齐、verify-workspace.* 空列表改为报错、新增 .gitattributes 保证 LF 检出
恒失败接口 group、relation、initial、feed、logs 的列名/键名/占位问题修正address 命名返回值修复social 三服务的 gateway 接线与聚合注册补齐
静默故障 sender 腾讯云短信空实现改为显式报错、日限额与黑名单真正生效、验证码 SetNX 与重放问题修正logs 的 IP 过滤方向、分页、panic 修正

校验

全部 21 个 module18 业务服务 + pkgs/all + pkgs/ecmall + scripts/api-docgen)均通过 GOWORK=off go build ./...GOWORK=off go vet ./...gofmt -lpkgs/allpkgs/ecmallmodule/base/fts 的既有单测通过(fts 新增的路径穿越防护用例由失败转通过)。module/base/sendertest/grpc/*_test.gointegration 构建标签、需要真实服务,不在 go test ./... 范围内执行。

说明:在仓库根以 workspace 模式编译会报 genproto 拆包的 ambiguous import,属本机既有的依赖解析问题;各模块内以 GOWORK=off 模块模式编译正常,本轮即以此校验。

部署前置(本次整改新增/强化的环境变量)

以下变量未提供时服务将拒绝启动或明确报错,不再回退到仓库中的公开样例值:

环境变量 用途 未配置后果
BSM_JwtSecretKey 聚合入口 JWT 签名密钥16/24/32 字节,须为私有值) pkgs/allpkgs/ecmall 启动即 log.Fatalln 并给出中文提示;公开样例值同样被拒
BSM_SECRET_KEY 聚合入口 session cookie 的 HMAC 密钥 启动即拒绝(空值或 CHANGE_ME 均不可用)
BSM_MGT_SECRET_KEY 聚合内 mgt 子配置的密钥 prod/test 配置以 ${BSM_MGT_SECRET_KEY} 占位,需部署时注入
BSM_CloudPrivateKey cloud 私人资料内容的 AES-GCM 加解密密钥≥16 字节) 私人资料写入/读取返回内部错误,不再以公开默认密钥「假加密」
BSM_MGT_ROOT_PASSWORD mgt 初始超级管理员口令 不再创建 123456;未设置时 root 口令为空、不可登录(日志提示)
BSM_DB_DSNBSM_MINIO_*BSM_ALIPAY_*BSM_JUMIO_* 数据库、对象存储、支付与 KYC 渠道凭据 各模块 etc/*.yaml 已统一改为 ${...} 占位,不再硬编码真实凭据

仓库中原有的真实库口令(Weidong1214)、弱口令(123456)与公开 JWT 样例密钥(Cblocksmesh2022C)已从 module/pkgs/scripts/ 全量清除。

仍未处理

  • 各报告中「中」「低」级别项:分页上限、死代码/死配置、README 与实现不符、reflection 与 TLS、XFF 可信性、登录限流、CI 接入、单测覆盖等。
  • 需新增契约字段才能完整实现的项目feed/cms 的互动去重缺「谁点过」记录表、mall 许可码校验(缺数据源)、部分角色的细粒度权限判定。
  • 历史数据迁移:库中此前的 MD5 / 明文口令记录无法被 bcrypt 校验,需通过「重置密码」流程迁移(整改后重置将写入 bcrypt
  • 全仓单测覆盖仍然薄弱,第六节第 5 条「补护栏」尚未执行。