文件密码与安全机制说明
一、设计目标概述
预览服务在处理 加密文件(加密 Office、PDF、压缩包、EPUB 等)时,引入了一套“基于 clientId 的密码解锁缓存机制”,目标是:
- 避免用户在短时间内重复输入密码
- 防止密码以明文形式落盘或长期存储
- 在保证安全性的前提下,提升加密文件的预览体验
核心策略一句话概括:
密码只在校验通过后短暂存在于服务端缓存中,并且始终以加密形式存储,过期即失效。
二、核心配置:fileview.preview.security.password
yaml
fileview:
preview:
security:
password:
# 密码解锁状态 TTL(秒)
ttlSeconds: 1800
# 密码加密密钥(生产环境建议由 KMS / 配置中心注入)
crypto:
secret: preview-default-secret-key-change-in-production配置含义说明
| 配置项 | 说明 | 默认值 |
|---|---|---|
ttlSeconds | 已解锁状态在缓存中的有效期(秒) | 1800(30 分钟) |
crypto.secret | 用于派生 AES 密钥的应用级秘密 | 默认内置 |
含义解释:
ttlSeconds- 同一个客户端(
clientId)对同一个文件(fileId)成功解锁后,在 TTL 时间内再次访问,无需重新输入密码。
- 同一个客户端(
crypto.secret- 用于对用户输入的密码进行 AES-GCM 对称加密,确保密码在 Redis 中始终以密文形式存在。
注意
当前代码实际读取的配置前缀为 preview.security.password.*,如果只在 fileview.preview.security.* 下配置,运行时仍会使用默认值。
这是一个需要在生产部署前统一配置前缀的问题。
三、密码的安全存储策略
1. 密码不会明文存储
用户输入的密码在写入缓存前:
- 使用 AES-256-GCM 算法加密
- 每次加密都会生成随机 IV
Redis 中存储的始终是:
- 加密后的密码,而非明文
2. 解锁状态与密码分离存储
在 Redis 中,针对同一个文件和客户端,会写入两类 key:
- 解锁状态标记:
unlock:preview:{fileId}:{clientId}
- 加密后的密码:
unlock:preview:pwd:{fileId}:{clientId}
两者具有相同的 TTL(由 ttlSeconds 控制):
- TTL 到期后:
- 解锁状态失效
- 密码自动清除
- 再次访问需要重新输入密码
四、对外解锁流程说明(接口级)
1. 密码解锁接口
POST /preview/api/password/unlock
解锁流程:
- 客户端提交:
- 文件标识(
fileId/originalFilePath) - 密码
- 文件标识(
- 服务端校验密码是否正确:
- 压缩包:验证是否可正常解压
- Office / PDF:验证加密状态与密码合法性
- 校验成功后:
- 写入「已解锁状态」
- 写入「加密后的密码」
- 设置 TTL(默认 30 分钟)
返回结果示例:
密码正确:
json{ "valid": true, "passwordCorrect": true }密码错误:
json{ "valid": false, "passwordCorrect": false, "passwordRequired": true }
2. 解锁状态查询接口
GET /preview/api/password/status?fileId=xxx
根据 fileId + clientId 判断:
- 是否存在有效的解锁状态
常用于:
- 前端判断是否需要再次弹出密码输入框
五、密码机制在预览流程中的实际作用
1. 缓存命中 ≠ 一定可预览
即使:
- 文件已经转换成功
- 预览结果已存在缓存
但如果文件是加密文件,且当前 clientId 未在 TTL 内解锁:
- 仍然会返回:
PASSWORD_REQUIRED - 强制用户先完成密码解锁流程
✅ 这是为了防止「他人复用已缓存的加密文件预览结果」。
2. 已解锁文件的密码复用
在 TTL 有效期内:
- 同一
clientId再次预览同一文件:- 服务端可从缓存中恢复已验证的密码
- 自动传递给转换 / 解压流程
- 用户无需重复输入密码
适用场景包括:
- 多次刷新页面
- 多页压缩包 / EPUB 连续访问
- 失败重试后再次预览
六、与缓存 / 长轮询机制的关系
- 密码解锁状态本身是缓存的一部分
- 长轮询过程中:
- 每次检查转换结果时
- 同时校验解锁状态是否仍然有效
若解锁 TTL 已过期:
- 即使转换成功
- 也会中断轮询并返回
PASSWORD_REQUIRED
七、安全性总结
这套文件密码机制具备以下特性:
- ✅ 密码不明文存储
- ✅ 密码自动过期
- ✅ 解锁状态与客户端隔离(基于
clientId) - ✅ 缓存结果无法绕过密码校验
- ✅ 可与缓存、长轮询、转换流程无缝协作
八、一句话总结
预览服务通过基于
clientId的密码解锁缓存机制,在保证密码安全的前提下,实现了加密文件“一次验证、短期复用、自动失效”的预览体验,有效平衡了安全性与易用性。