Files
caiwuzongzhang/docs/decisions/003-auth.md
T
腾讯WorkBuddy 7f1a93f6a6 B-64: 安全修复——随机初始密码与跨公司重复上传隔离
- 公司账号创建改为随机一次性初始密码,只在创建响应中显示一次,
  密码保证不等于用户名;删除「用户名即初始密码」兼容分支,继续
  强制首次登录改密。
- 跨公司相同字节文件上传只返回通用重复状态:不再返回其他公司的
  原批次 ID、银行、模板、期间、交易数或诊断;同公司重复上传的
  幂等摘要保持可用。
- 补充服务端回归测试,覆盖同公司与跨公司两个分支及随机密码;
  完整测试 85 项全绿,node --check 通过。
2026-08-16 01:50:42 +08:00

3.7 KiB
Raw Blame History

003 身份认证与租户隔离技术决策

对应 IssueB-40docs/issues/003-p0-auth-and-tenant-isolation.md)。

密码散列:标准库 PBKDF2-HMAC-SHA256

  • 只使用 Python 标准库(hashlib.pbkdf2_hmac + hmac.compare_digest + secrets),不引入 bcrypt/argon2 等第三方依赖,与离线内网部署约束一致。
  • 260 000 次迭代、16 字节随机盐,存储格式 pbkdf2_sha256$<迭代数>$<盐hex>$<摘要hex>,自描述、可平滑升级参数。
  • 明文密码永不入库、永不进日志、永不写入 audit_log password_hash 字段从不出现在任何 API 响应中(有测试断言)。

会话:数据库保存令牌摘要,8 小时绝对过期

  • 令牌为 secrets.token_urlsafe(32),数据库只存其 SHA-256 摘要; 数据库泄露不直接暴露可用令牌。
  • 绝对过期 8 小时(一个工作班次),不做滑动续期,语义简单可测。
  • 会话可吊销:退出登录、停用账号、重置密码都会立即吊销该用户全部会话。
  • Cookie 名 cw_sessionHttpOnly; SameSite=Lax; Path=/。 当前是纯 HTTP 的局域网部署,刻意不加 Secure(加了浏览器会直接拒发); 若未来上 HTTPS,应补上 Secure 并配置反向代理。

登录限流:同一 (账号, IP) 10 分钟内失败 5 次即锁定

  • 计数来自 login_attempts 表,窗口为滚动 10 分钟;触发后返回 429, 且在窗口内不再记录新尝试,行为确定、可测试。
  • 失败提示统一为「账号或密码不正确」,不泄露是哪一部分错误。

角色与公司绑定

  • users.roleadmin / company;数据库 CHECK 约束强制 公司账号必须绑定公司、管理员不得绑定公司。
  • 登录时前端选择工作端口(portal),服务端校验 portal 与角色一致, 不匹配返回 403「账号与该工作端口不匹配」。
  • 管理员创建公司账号时,初始密码为随机一次性密码并置 must_change_password=1;首次登录必须改密,改密前所有业务 API 返回 403。 初始密码只在创建成功响应中显示一次,永不入库明文、永不写日志; 创建用户的审计 detail 只记录公司,不重复账号名。
  • 「重置密码」同样生成随机一次性密码并吊销既有会话。

租户隔离在服务端强制,404 优于 403

  • 公司用户的批次列表、行明细、CSV 导出、上传归属全部由服务端按 会话中的 company_id 过滤;请求体/参数里的 company_id 对公司用户 一律忽略(跨公司上传防护)。
  • 访问他公司批次返回 404 而非 403:不暴露「该批次存在但属于别人」这一事实, 避免 IDOR 探测。导出时显式指定他公司 company_id 仍返回 403, 因为用户已声明知道该公司存在,此时给出明确拒绝更有操作性。
  • GET /admin.html/company.html 的 302 跳转只是 UX 层引导, 不是权限边界;真正的边界全部在 API 上。

引导管理员(bootstrap

  • 服务启动迁移后若无任何 admin 账号,创建 APP_ADMIN_USERNAME (默认 group-admin);密码取 APP_BOOTSTRAP_ADMIN_PASSWORD 未设置则生成随机初始密码并只打印一次到 stdout(不写日志文件), must_change_password=1
  • 不在迁移或代码中预置任何公司或用户;公司与公司账号全部由管理员 通过 /api/admin/companies/api/admin/users 动态创建。

审计

  • audit_log 记录登录成功/失败、退出、改密、上传、导出(含公司范围与行数)、 建公司、建/停/启用户、重置密码等动作,含操作者、目标、IP、时间。
  • 初始密码、新旧密码均不进入审计内容。