95 lines
2.1 KiB
Markdown
95 lines
2.1 KiB
Markdown
# Center ↔ Guild 注册握手协议 v1(HMAC)
|
||
|
||
## 1. 目标
|
||
- 让 Guild Node 在注册时证明自己持有共享密钥(`CENTER_SHARED_SECRET`)
|
||
- 防止中间人篡改与重放攻击
|
||
|
||
---
|
||
|
||
## 2. 注册接口
|
||
- **Method:** `POST`
|
||
- **Path:** `/api/nodes/register`
|
||
- **Content-Type:** `application/json`
|
||
|
||
### Body
|
||
```json
|
||
{
|
||
"nodeId": "guild-node-1",
|
||
"name": "Guild Node 1",
|
||
"endpoint": "http://guild-node-1:7002"
|
||
}
|
||
```
|
||
|
||
### Required Headers
|
||
- `X-Fabric-Version`: 协议版本,当前固定为 `1`
|
||
- `X-Fabric-Timestamp`: ISO8601 UTC 时间(如 `2026-05-12T11:00:00.000Z`)
|
||
- `X-Fabric-Nonce`: 随机字符串(建议 UUID)
|
||
- `X-Fabric-Signature`: HMAC-SHA256 十六进制串
|
||
|
||
---
|
||
|
||
## 3. Canonical String
|
||
签名输入格式(换行拼接):
|
||
|
||
```text
|
||
{METHOD}\n{PATH}\n{TIMESTAMP}\n{NONCE}\n{BODY_JSON}
|
||
```
|
||
|
||
示例:
|
||
```text
|
||
POST
|
||
/api/nodes/register
|
||
2026-05-12T11:00:00.000Z
|
||
f8b3a8dc-3aeb-44fc-a4a1-36f8b6c27739
|
||
{"nodeId":"guild-node-1","name":"Guild Node 1","endpoint":"http://guild-node-1:7002"}
|
||
```
|
||
|
||
签名算法:
|
||
```text
|
||
signature = HMAC_SHA256_HEX(CENTER_SHARED_SECRET, canonicalString)
|
||
```
|
||
|
||
---
|
||
|
||
## 4. Center 侧校验规则
|
||
1. 必须包含三项头:`signature/timestamp/nonce`
|
||
2. `timestamp` 与服务端时间偏差不超过 5 分钟
|
||
3. 使用相同 canonical 规则重新计算签名
|
||
4. `timingSafeEqual` 比较签名
|
||
5. 签名通过后再做业务校验:
|
||
- nodeId 唯一
|
||
- endpoint 唯一
|
||
|
||
---
|
||
|
||
## 5. 响应语义
|
||
### 成功
|
||
- `200 OK`
|
||
- body 含 `status: accepted` 与 node 信息
|
||
|
||
### 失败(建议)
|
||
- `403`:签名头缺失/签名错误/时间窗非法
|
||
- `409`:nodeId 或 endpoint 冲突
|
||
- `400`:参数非法
|
||
|
||
---
|
||
|
||
## 6. 安全建议
|
||
- `CENTER_SHARED_SECRET` 长度至少 32 字节
|
||
- 定期轮换 secret(可采用双 key 过渡)
|
||
- 在网关层启用 HTTPS
|
||
- 后续可增加 nonce 去重表,防止时间窗内重放
|
||
|
||
---
|
||
|
||
## 7. 版本协商(预留)
|
||
当前版本:`v1`
|
||
|
||
当前实现要求请求头:
|
||
- `X-Fabric-Version: 1`
|
||
|
||
若版本不匹配,Center 返回:
|
||
- `400`
|
||
- `error.code = FABRIC_VERSION_NOT_SUPPORTED`
|
||
- `supportedVersion = "1"`
|