spec.md 7.1 KB

Security Sensitive Data Hardening

status: done

背景

当前安全评估指出 5 类敏感信息与上传面风险:

  • /system/config/page 返回系统参数时暴露 sys.user.initPassword 明文默认密码。
  • /system/user/page 返回用户分页时包含 passwordsalt 等认证字段,并直接暴露手机号、身份证号等 PII。
  • /system/cache/page/system/cache/getInfo 可枚举 Redis 敏感键和值,包括加密会话密钥、Sa-Token token/session 等。
  • /system/storage/config/default 可能返回 OSS AccessKey/SecretKey 等云存储凭据。
  • /api/file/upload 允许认证用户上传 HTML、JSP、PHP 等高风险文件,文件类型校验依赖存储配置且默认配置可能为空。

目标

  1. 系统配置接口不再返回密码、密钥、token、secret 等敏感配置明文。
  2. 用户分页、详情、个人资料接口不再返回密码哈希和盐;用户列表手机号、身份证号等 PII 默认脱敏。
  3. 缓存管理接口只允许超级管理员访问,并对敏感缓存键做列表过滤、详情拒绝、删除保护。
  4. 文件存储配置普通上传场景只返回安全元数据,管理接口返回的 AK/SK 默认脱敏。
  5. 上传接口强制执行安全文件类型策略:限制扩展名、拒绝脚本/网页可执行类文件、校验 MIME 与扩展名基本一致。
  6. 增加用户级强制改密标记,支持“初始密码/管理员重置后首次登录必须修改密码”。
  7. 迁移脚本清空默认密码配置、为存量用户标记强制改密、补齐默认上传白名单。

非目标

  • 不在代码中提交新的固定默认密码。
  • 不在代码中硬编码本次泄露的真实密码、AK/SK。
  • 不直接替生产环境吊销云厂商密钥;该动作必须由运维在云平台完成。
  • 不静默生成用户新密码并通知用户;生产批量密码重置需要配套短信、邮件或人工通知流程。

设计

1. 系统配置敏感值处理

  • 新增统一敏感键判断工具,识别包含 passwordsecrettokenkeycredentialaksk 等关键字的配置键。
  • SysConfigController 对 page/list/detail 返回对象做脱敏拷贝,敏感 configValue 返回 ******
  • /system/config/configKey/{configKey} 对敏感配置键拒绝返回明文。
  • SysConfigServiceImpl.updateConfig 对敏感配置支持“脱敏占位值不更新原值”,避免前端保存 ****** 覆盖真实值。
  • sys.user.initPassword 作为高危默认密码配置,通过迁移脚本清空并停用。

2. 用户数据返回面收口

  • SysUser.passwordSysUser.salt 使用 @JsonIgnore,从所有 JSON 响应中排除。
  • 新增 forcePasswordChange 字段,用于登录态强制改密。
  • /system/user/page 返回前对 phoneidCardemail 做脱敏;详情接口只清空认证字段,不脱敏需要编辑的字段。
  • /auth/userInfo/system/user/profile 返回前清空认证字段,并保留 forcePasswordChange 供前端判断。

3. 强制改密

  • sys_user 新增 force_password_change,默认 0
  • 新增用户、管理员重置密码时设置为 1
  • 用户通过 /auth/changePassword 修改成功后设置为 0
  • 登录构建 LoginUser 时带出 forcePasswordChange
  • ApiPermissionInterceptor 在 API 权限判断前检查登录用户强制改密状态;若为 true,只允许访问 /auth/userInfo/auth/changePassword/auth/logout 和必要密钥交换接口。
  • 前端登录后如发现 forcePasswordChange=true,跳转 /profile 并提示必须改密;路由守卫阻止访问其他页面。

4. 缓存敏感键保护

  • SysCacheController 定义敏感缓存键前缀/模式:
    • crypto:session:*
    • Authorization:login:token:*
    • Authorization:login:token-session:*
    • Authorization:login:last-active:*
    • satoken:*
    • auth:sso:*
  • 分页列表默认过滤敏感键,不返回 key 和 valuePreview。
  • 精确查询、删除、批量删除、按模式清理遇到敏感键时拒绝操作。
  • 保留超级管理员访问控制;敏感键仍不能通过缓存接口读取值。

5. 文件存储配置凭据保护

  • /system/storage/config/default 继续返回上传组件所需安全字段,不含 endpoint/accessKey/secretKey/bucket/domain/basePath。
  • 管理类 page/detail 返回的 accessKeysecretKey 脱敏显示。
  • 新增/编辑保存时,若前端提交脱敏占位值,不覆盖原凭据。
  • /system/storage/config/options 保持只返回 id、configName、storageType、isDefault、enabled。

6. 上传安全校验

  • FileManager 对所有 MultipartFile 和流式上传统一执行:
    • 文件名非空、扩展名非空。
    • 高风险扩展名拒绝:jsp,jspx,php,asp,aspx,html,htm,js,mjs,ts,vue,sh,bat,cmd,exe,dll,jar,war,ear,sql 等。
    • 若存储配置未配置 allowedTypes,使用默认安全白名单:jpg,jpeg,png,gif,webp,pdf,doc,docx,xls,xlsx,txt,csv,zip,rar,mp4,mp3
    • MIME 与扩展名做基础匹配,高风险脚本 MIME 拒绝。
    • 最大文件大小无配置时使用安全默认值。
  • 分片上传初始化也校验文件名扩展名;分片内容无法完整 MIME 扫描,保留完成后元数据保存前的文件名策略。

数据库迁移

新增 V1.0.67__harden_sensitive_data_and_upload_controls.sql

  • sys_user 增加 force_password_change tinyint(1) NOT NULL DEFAULT 0
  • 存量用户 force_password_change=1,用于强制所有已存在账号下次登录先改密。
  • sys_configsys.user.initPassword 清空 config_value 并设置为停用或非系统内置。
  • sys_file_storage_config.allowed_types 为空时回填默认安全白名单,并移除 svgmd 等容易承载主动内容的默认公共上传类型。

验收标准

  • /system/config/page/system/config/getById 不返回 sys.user.initPassword 明文。
  • /system/user/page 响应不含 passwordsalt,手机号/身份证号已脱敏。
  • /system/cache/page 不出现 crypto:sessionAuthorization:loginsatoken 等敏感缓存键;getInfo/remove/clear 不能操作这些键。
  • /system/storage/config/default 不含 AK/SK;管理页只显示脱敏值。
  • /api/file/upload 上传 .jsp.php.html.js 等文件失败。
  • 被标记 forcePasswordChange=true 的用户登录后只能访问改密相关接口,改密成功后恢复正常访问。

生产处置要求

  • 立即吊销评估报告中已泄露的 OSS AccessKey/SecretKey,并替换为最小权限新密钥。
  • 批量重置所有仍使用泄露默认密码的账号密码;如无法立即通知用户,至少临时禁用或锁定风险账号。
  • 开启 OSS 访问日志、异常告警和必要的 IP 白名单。
  • 对用户枚举、批量登录失败、缓存管理、文件上传增加审计关注。

归档记录(HARD-GATE)

  • 状态:done
  • 归档时间:2026-06-27
  • 归档人:yaomd(批量归档)
  • 归档路径:code-copilot/changes/archive/2026-06-27-security-sensitive-data-hardening/
  • 判定依据:任务清单全部完成,execution-log 验证通过(编译/构建/lint 闭环)。