130 lines
6.4 KiB
Markdown
130 lines
6.4 KiB
Markdown
# 传输层加解密配置说明
|
||
|
||
## 模式说明
|
||
|
||
`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"}]'
|
||
```
|