128 lines
3.9 KiB
Markdown
128 lines
3.9 KiB
Markdown
# 接口安全校验与请求/响应加密说明
|
||
|
||
本文档说明系统已有的两套机制:
|
||
1. 安全校验(请求头签名)
|
||
2. 请求/响应参数加解密(AES-GCM)
|
||
|
||
并给出前端对接方式与示例。
|
||
|
||
## 一、机制概览
|
||
|
||
### 1. 安全校验(签名)
|
||
- 入口中间件:`server/middleware/security.go`
|
||
- 目的:防止非法请求与重放
|
||
- 校验内容:请求头签名 + 时间戳
|
||
- 有效期:5 分钟内
|
||
- 白名单:`/swagger/`、`/swagger/index.html`
|
||
|
||
### 2. 请求/响应加解密(Payload Crypto)
|
||
- 入口中间件:`server/middleware/payload_crypto.go`
|
||
- 加密算法:AES-GCM,密钥来自 `payload_crypto.secret_key`
|
||
- 加密载荷结构:
|
||
- `nonce`:Base64
|
||
- `ciphertext`:Base64
|
||
- 可独立控制:
|
||
- 仅加密响应
|
||
- 仅解密请求
|
||
- 请求强制加密
|
||
|
||
## 二、当前开发环境默认行为(config.dev.yaml)
|
||
|
||
- `security.enable = false`
|
||
- 不要求签名头
|
||
- `payload_crypto.enable = true`
|
||
- 框架开启,但请求/响应方向开关关闭
|
||
- `payload_crypto.request.enable = false`
|
||
- `payload_crypto.response.enable = false`
|
||
|
||
结论:开发环境默认不需要前端计算签名,也不会返回加密响应。
|
||
|
||
## 三、前端对接方式
|
||
|
||
### 1. 安全校验(签名)对接
|
||
|
||
当 `security.enable = true` 时必须携带:
|
||
- `X-App-Timestamp`:毫秒时间戳
|
||
- `X-App-Sign`:`MD5(timestamp + secretKey)`
|
||
- `secretKey` 来自 `security.secret_key`
|
||
|
||
请求示例(伪代码):
|
||
```text
|
||
timestamp = 当前毫秒时间戳
|
||
sign = md5(timestamp + secretKey)
|
||
Headers:
|
||
X-App-Timestamp: <timestamp>
|
||
X-App-Sign: <sign>
|
||
```
|
||
|
||
注意:
|
||
- 服务器允许时间偏差 5 分钟。
|
||
- 若请求不在白名单且缺少签名或时间戳,将返回 403。
|
||
|
||
### 2. 请求加密(可选)
|
||
|
||
当 `payload_crypto.enable = true` 且 `payload_crypto.request.enable = true` 时:
|
||
- 若 `payload_crypto.request.required = true`,所有请求必须加密。
|
||
- 若 `required = false`,是否加密由请求头决定。
|
||
|
||
请求头:
|
||
- `X-App-Encrypt: 1`(头名来自 `payload_crypto.header_key`)
|
||
|
||
请求体格式(JSON):
|
||
```json
|
||
{
|
||
"nonce": "Base64Nonce",
|
||
"ciphertext": "Base64Ciphertext"
|
||
}
|
||
```
|
||
|
||
加解密规则:
|
||
- AES-GCM
|
||
- nonce 长度使用 GCM 标准长度(12 bytes,编码后为 Base64 字符串)
|
||
- 明文为原始 JSON 请求体
|
||
|
||
### 3. 响应加密(可选)
|
||
|
||
当 `payload_crypto.enable = true` 且 `payload_crypto.response.enable = true` 时:
|
||
- 服务端返回加密响应
|
||
- 响应头会带:`X-App-Encrypt: 1`
|
||
- 响应体同样为:
|
||
```json
|
||
{
|
||
"nonce": "Base64Nonce",
|
||
"ciphertext": "Base64Ciphertext"
|
||
}
|
||
```
|
||
|
||
前端处理流程:
|
||
1. 判断响应头 `X-App-Encrypt` 是否为真(非空、非 0、非 false)。
|
||
2. 若为真,用 `payload_crypto.secret_key` 进行 AES-GCM 解密。
|
||
3. 解密得到的明文即为原始 JSON 响应。
|
||
|
||
## 四、密钥派生规则(前端需要一致)
|
||
|
||
加密密钥派生规则在 `server/common/payload_crypto.go`:
|
||
1. 若 `secret_key` 是 Base64,且解码后长度为 16/24/32 字节,直接使用。
|
||
2. 否则若 `secret_key` 的原始长度为 16/24/32 字节,直接使用原始字节。
|
||
3. 否则对 `secret_key` 做 SHA-256,取 32 字节作为 AES key。
|
||
|
||
前端必须严格按上述规则派生密钥,否则无法解密。
|
||
|
||
## 五、建议的对接策略
|
||
|
||
- 开发联调:先关闭签名与加密,仅验证业务流程。
|
||
- 灰度/生产:
|
||
- 开启 `security.enable`,强制签名校验。
|
||
- 按需开启 `payload_crypto.response.enable`,保护敏感响应。
|
||
- 若需要强制请求加密,再开启 `payload_crypto.request.required`。
|
||
|
||
## 六、相关配置位置
|
||
|
||
- 安全校验配置:`server/config/config.*.yaml` -> `security` 段
|
||
- 加解密配置:`server/config/config.*.yaml` -> `payload_crypto` 段
|
||
- 中间件实现:
|
||
- `server/middleware/security.go`
|
||
- `server/middleware/payload_crypto.go`
|
||
- 加解密工具:`server/common/payload_crypto.go`
|
||
|