ShiErFeng/shierfeng-fastapi-backend/docs/transport_crypto_config.md
2026-07-24 09:43:10 +08:00

130 lines
6.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 传输层加解密配置说明
## 模式说明
`TRANSPORT_CRYPTO_MODE` 共有三种模式:
- `off`
完全关闭传输层加解密。中间件不执行请求解密与响应加密,前端通过 `/transport/crypto/frontend-config` 获取到的策略也会同步关闭。
- `optional`
可选加密模式。命中的接口既接受明文请求,也接受加密请求;如果请求已加密,后端会解密后处理,并对命中的 JSON 响应自动加密。适合灰度接入和上线初期观察。
- `required`
强制加密模式。命中的接口必须携带合法加密信封明文请求会被直接拒绝同时防重放校验会按严格模式执行Redis 不可用时也会拒绝请求。适合链路稳定后的正式强制启用阶段。
补充说明:
- `TRANSPORT_CRYPTO_ENABLED=false` 时,整体效果等同于关闭,不再进入传输层加解密逻辑。
- `TRANSPORT_CRYPTO_ENABLED_PATHS`、`TRANSPORT_CRYPTO_REQUIRED_PATHS` 和 `TRANSPORT_CRYPTO_EXCLUDE_PATHS` 会在上述模式基础上继续约束命中范围。
## 开发环境
开发环境直接使用 `.env.dev` 中默认提供的可用密钥对即可。
说明:
- 传输层加解密启用后,后端启动时必须读到一对匹配的 `TRANSPORT_CRYPTO_PUBLIC_KEY` / `TRANSPORT_CRYPTO_PRIVATE_KEY`
- 前端会自动读取 `/transport/crypto/frontend-config`,并跟随后端配置完成请求加密、响应解密。
- `/transport/crypto/frontend-config``/transport/crypto/public-key` 为公开接口,已配置匿名限流,前端会直接调用这两个接口完成初始化。
- `TRANSPORT_CRYPTO_FRONTEND_CONFIG_TTL_SECONDS` 用于控制前端多久重新拉取一次运行策略。
- `TRANSPORT_CRYPTO_PUBLIC_KEY_TTL_SECONDS` 用于控制前端多久重新拉取一次公钥,两者已经独立。
## 生产环境
生产环境使用后端 `.env.prod` 中的密钥配置;仓库默认提供一套可用示例值,正式部署前请替换为正式密钥。
推荐最小配置如下:
```env
TRANSPORT_CRYPTO_ENABLED=true
TRANSPORT_CRYPTO_MODE='optional'
TRANSPORT_CRYPTO_KID='2026-prod-v1'
TRANSPORT_CRYPTO_PUBLIC_KEY='-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----\n'
TRANSPORT_CRYPTO_PRIVATE_KEY='-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n'
TRANSPORT_CRYPTO_LEGACY_KEY_PAIRS='[]'
TRANSPORT_CRYPTO_FRONTEND_CONFIG_TTL_SECONDS=300
TRANSPORT_CRYPTO_PUBLIC_KEY_TTL_SECONDS=3600
TRANSPORT_CRYPTO_CLOCK_SKEW_SECONDS=120
TRANSPORT_CRYPTO_MAX_GET_URL_LENGTH=4096
```
说明:
- `TRANSPORT_CRYPTO_PUBLIC_KEY``TRANSPORT_CRYPTO_PRIVATE_KEY` 必须是一对匹配密钥,缺一不可。
- `TRANSPORT_CRYPTO_KID` 表示当前启用的密钥版本。
- `TRANSPORT_CRYPTO_FRONTEND_CONFIG_TTL_SECONDS` 控制 `/transport/crypto/frontend-config` 的前端缓存时长,适合在策略经常调整时适当缩短。
- `TRANSPORT_CRYPTO_PUBLIC_KEY_TTL_SECONDS` 控制 `/transport/crypto/public-key` 的前端缓存时长,主要服务于公钥缓存与密钥轮换。
- `TRANSPORT_CRYPTO_CLOCK_SKEW_SECONDS` 建议控制在 `60-120` 秒,默认收紧为 `120` 秒。
- `TRANSPORT_CRYPTO_REPLAY_TTL_SECONDS` 控制防重放随机数在 Redis 中的有效期;如果准备使用 `required` 模式,建议保证 Redis 稳定可用。
- 初次上线建议先用 `TRANSPORT_CRYPTO_MODE='optional'`,确认链路稳定后再考虑切到 `required`
- `TRANSPORT_CRYPTO_MAX_GET_URL_LENGTH` 用于限制 GET/DELETE 请求加密后的 URL 长度,前端会通过 `/transport/crypto/frontend-config` 自动同步该值,超限时直接提示改用 POST 或精简查询条件。
- 传输层加密主要面向查询参数、`application/json` 与 `application/x-www-form-urlencoded` 请求;`multipart/form-data` 上传和下载接口默认排除。
## Docker 环境
当前项目的 Docker 部署使用:
- `shierfeng-fastapi-test/docker-compose.test.my.yml` + `shierfeng-fastapi-backend/Dockerfile.my`
- `shierfeng-fastapi-test/docker-compose.test.pg.yml` + `shierfeng-fastapi-backend/Dockerfile.pg`
后端容器启动命令分别是:
- `shierfeng app run --env=dockermy`
- `shierfeng app run --env=dockerpg`
所以 Docker 环境需要直接在以下文件中配置传输层密钥:
- `shierfeng-fastapi-backend/.env.dockermy`
- `shierfeng-fastapi-backend/.env.dockerpg`
配置方式与生产环境相同;`.env.dockermy` / `.env.dockerpg` 里也已经默认提供一套可用示例值,正式部署前请替换为正式密钥。
使用时只需要:
1. 修改对应的 `.env.dockermy``.env.dockerpg`
2. 重新构建并启动 Docker 服务
## 密钥生成
使用 `openssl` 生成一套 RSA 密钥:
```bash
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:4096 -out transport_private.pem
openssl rsa -pubout -in transport_private.pem -out transport_public.pem
```
如果需要写入 `.env`,先转成单行带 `\n` 的格式:
```bash
awk 'NF {sub(/\r/, ""); printf "%s\\\\n",$0;}' transport_private.pem
awk 'NF {sub(/\r/, ""); printf "%s\\\\n",$0;}' transport_public.pem
```
## 使用流程
1. 后端启动时读取当前 `TRANSPORT_CRYPTO_*` 配置,并校验公私钥是否同时存在且彼此匹配。
2. 前端通过 `/transport/crypto/frontend-config` 获取当前运行策略,再通过 `/transport/crypto/public-key` 获取当前 `kid`、协议版本和公钥。
3. `TRANSPORT_CRYPTO_FRONTEND_CONFIG_TTL_SECONDS``TRANSPORT_CRYPTO_PUBLIC_KEY_TTL_SECONDS` 分别控制这两类缓存的刷新周期。
4. 前端用公钥加密请求,后端用私钥解密请求。
5. 后端会对命中的 JSON 响应自动加密,前端自动解密;下载、上传等排除场景保持明文。
## 密钥轮换
如果需要更换密钥:
1. 生成新密钥对。
2. 修改 `TRANSPORT_CRYPTO_KID` 为新版本,例如 `2026-prod-v2`
3. 配置新的 `TRANSPORT_CRYPTO_PUBLIC_KEY``TRANSPORT_CRYPTO_PRIVATE_KEY`
4. 把旧私钥放入 `TRANSPORT_CRYPTO_LEGACY_KEY_PAIRS`
补充说明:
- `TRANSPORT_CRYPTO_LEGACY_KEY_PAIRS` 主要用于兼容旧报文解密,最少提供 `kid` 和旧私钥即可;`publicKey` 可选,不填时后端会从私钥推导。
- 轮换期间建议保留旧私钥直到旧公钥缓存全部过期,至少覆盖 `TRANSPORT_CRYPTO_PUBLIC_KEY_TTL_SECONDS` 对应的缓存窗口。
示例:
```env
TRANSPORT_CRYPTO_KID='2026-prod-v2'
TRANSPORT_CRYPTO_LEGACY_KEY_PAIRS='[{"kid":"2026-prod-v1","privateKey":"-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n"}]'
```