主题
IPC 云端通信:认证与安全机制
双密钥模型
| 密钥 | 用途 | 持有方 |
|---|---|---|
SN_Secret | HTTPS 上行签名(IPC→FCC/CPC) | IPC、FCC、CPC |
FitronClientSecret | HTTPS 签名(CPC→FCC) | CPC、FCC |
DeviceSecret | MQTT TLS 连接鉴权 | IPC、IoT 平台 |
密钥交付方式:
SN_Secret:出厂烧录到设备,FCC 数据库存根FitronClientSecret:部署客户私有云时线下交付(不涉及线上传输),FCC 数据库存根DeviceSecret:设备注册时由 IoT 平台生成并下发
SN_Secret 签名规则
| 项目 | 规则 |
|---|---|
| 算法 | HMAC-SHA256 |
| 密钥 | SN_Secret |
| 签名原文 | uppercase(SN) + ":" + TIMESTAMP + ":" + NONCE + ":" + BODY |
| SN | 与 X-SN 一致,参与签名时转为大写 |
| TIMESTAMP | Unix 秒级时间戳,与 X-Timestamp 一致 |
| NONCE | 与 X-Nonce 一致 |
| BODY | 请求体原始字符串;GET 请求为空字符串 "" |
| BODY 约束 | 不允许包含换行;参与签名前去除首尾空格 |
| 输出 | 64 位小写 hex |
签名计算示例(Python)
python
import hmac, hashlib
sn = "FT-A1B2C3D4-9F2E"
timestamp = "1768617100"
nonce = "a1b2c3d4e5f67890a1b2c3d4e5f67890"
body = '{"type":"report:device:heartbeat","msg_id":"550e8400-e29b-41d4-a716-446655440000","timestamp":1768617100,"sn":"FT-A1B2C3D4-9F2E","data":{"status":"online"}}'.strip()
canonical = f"{sn.upper()}:{timestamp}:{nonce}:{body}"
sign = hmac.new(sn_secret.encode(), canonical.encode(), hashlib.sha256).hexdigest()GET 请求签名
GET 请求无 body,BODY 取空字符串:
python
body = ""
canonical = f"{sn.upper()}:{timestamp}:{nonce}:{body}"
sign = hmac.new(sn_secret.encode(), canonical.encode(), hashlib.sha256).hexdigest()FitronClientSecret 签名规则(CPC → FCC)
CPC 调用 FCC 接口(/cpc/**)时使用 FitronClientSecret 签名,签名算法与 SN_Secret 一致,差异仅在身份标识 Header、参与签名的身份字段和密钥:
| 项目 | 规则 |
|---|---|
| 算法 | HMAC-SHA256 |
| 密钥 | FitronClientSecret |
| 签名原文 | ClientId + ":" + TIMESTAMP + ":" + NONCE + ":" + BODY |
| 身份标识 | X-Fitron-Client-Id(替代 X-SN) |
| BODY 约束 | 与 SN_Secret 规则一致 |
| 公共 Header | X-Request-ID、X-Timestamp、X-Nonce、X-Signature(与 IPC 一致) |
CPC → FCC Header 示例
http
POST /cpc/sn-secrets HTTP/1.1
Host: fcc-api.fitron.vip
Content-Type: application/json
X-Fitron-Client-Id: cpc-beijing-001
X-Request-ID: 550e8400-e29b-41d4-a716-446655440000
X-Timestamp: 1768617100
X-Nonce: a1b2c3d4e5f67890a1b2c3d4e5f67890
X-Signature: 7f8e9d6c5b4a3210fedcba9876543210abcdef0123456789abcdef0123456789两方签名差异对比
| 维度 | IPC → FCC / CPC | CPC → FCC |
|---|---|---|
| 身份 Header | X-SN | X-Fitron-Client-Id |
| 密钥 | SN_Secret(出厂烧录) | FitronClientSecret(部署时线下交付) |
| 签名原文 | uppercase(SN):TIMESTAMP:NONCE:BODY | uppercase(ClientId):TIMESTAMP:NONCE:BODY |
| 公共 Header | 完全一致 | 完全一致 |
HTTPS 请求头
工控机请求头(IPC → FCC / CPC)
| Header | 必填 | 说明 |
|---|---|---|
Content-Type | 是 | application/json |
X-SN | 是 | 设备序列号 |
X-Request-ID | 否 | UUID v4,日志追踪与幂等去重(推荐携带) |
X-Timestamp | 是 | Unix 秒级时间戳 |
X-Nonce | 是 | 32 位随机 hex |
X-Signature | 是 | HMAC-SHA256 签名 |
CPC 请求头(CPC → FCC)
| Header | 必填 | 说明 |
|---|---|---|
Content-Type | 是 | application/json |
X-Fitron-Client-Id | 是 | CPC 客户端标识 |
X-Request-ID | 否 | UUID v4,日志追踪与幂等去重(推荐携带) |
X-Timestamp | 是 | Unix 秒级时间戳 |
X-Nonce | 是 | 32 位随机 hex |
X-Signature | 是 | HMAC-SHA256 签名 |
HTTP 请求结构(统一约定)
所有 IPC -> Backend 的 POST 请求都拆为两部分:
Header:身份与安全信息(X-SN、X-Request-ID、X-Timestamp、X-Nonce、X-Signature)Body:业务数据(控制结果、扫脸数据、补偿记录等)
Header 与 Body 字段去重规则
- Header 中已有的字段,Body 可以不重复携带(推荐不重复)
- 业务端以 Header 为准进行身份识别与验签
- 若 Body 中仍带了同名字段(如
sn、timestamp),则必须与 Header 一致,否则按无效请求处理
Header 示例
http
POST /v1/ipc/report HTTP/1.1
Host: cpc.example.com
Content-Type: application/json
X-SN: FT-A1B2C3D4-9F2E
X-Request-ID: 550e8400-e29b-41d4-a716-446655440000
X-Timestamp: 1768617100
X-Nonce: a1b2c3d4e5f67890a1b2c3d4e5f67890
X-Signature: 7f8e9d6c5b4a3210fedcba9876543210abcdef0123456789abcdef0123456789验签与防重放
| 规则 | 要求 |
|---|---|
| 时间窗 | 请求时间差 <= 300 秒 |
| Nonce 唯一性 | 同一身份标识在 10 分钟窗口内不允许复用 |
| Nonce 隔离 | 按客户维度隔离去重,同一客户内不同设备/来源的 Nonce 互不干扰 |
| 比对策略 | 恒定时间比较 |
Nonce 存储建议
推荐实现:Redis + 10 分钟 TTL,按客户维度隔离。
| 来源 | Key 模式 | 说明 |
|---|---|---|
| IPC 请求 | fitron:nonce:{SN} | 按 SN 隔离 |
| CPC 请求 | fitron:nonce:cpc:{FitronClientId} | 按 CPC 客户端隔离 |
| 项目 | 建议 |
|---|---|
| 数据结构 | Set / Sorted Set |
| 清理策略 | 写入时清理过期值 + Key TTL 10 分钟 |
DeviceSecret MQTT 连接参数
| 参数 | 值 |
|---|---|
| Broker Host | {ProductID}.iot.tencentcloudapi.com |
| Broker Port | 8883 |
| ClientID | {ProductID}.{SN} |
| Username | {ProductID}{SN};120101;{ConnId};{Expiry} |
| Password | Base64(HMAC-SHA256(DeviceSecret, Username)) |
| KeepAlive | 60 秒 |
| CleanSession | true |
TLS 与密钥存储
- HTTPS 与 MQTT 均使用
TLS 1.2+ config_url仅允许 HTTPSSN_Secret/DeviceSecret禁止明文落盘- 出厂预置密钥仅用于首次注册场景,注册完成后应可擦除
安全待确认项
- 首次注册是否全部使用出厂预置密钥,还是统一直接烧录
SN_Secret - IPC 端密钥存储是否要求 TEE 或硬件安全模块
- Nonce 记录采用 Redis 还是数据库兜底