Skip to content

IPC 云端通信:认证与安全机制


双密钥模型

密钥用途持有方
SN_SecretHTTPS 上行签名(IPC→FCC/CPC)IPC、FCC、CPC
FitronClientSecretHTTPS 签名(CPC→FCC)CPC、FCC
DeviceSecretMQTT TLS 连接鉴权IPC、IoT 平台

密钥交付方式

  • SN_Secret:出厂烧录到设备,FCC 数据库存根
  • FitronClientSecret:部署客户私有云时线下交付(不涉及线上传输),FCC 数据库存根
  • DeviceSecret:设备注册时由 IoT 平台生成并下发

SN_Secret 签名规则

项目规则
算法HMAC-SHA256
密钥SN_Secret
签名原文uppercase(SN) + ":" + TIMESTAMP + ":" + NONCE + ":" + BODY
SNX-SN 一致,参与签名时转为大写
TIMESTAMPUnix 秒级时间戳,与 X-Timestamp 一致
NONCEX-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 规则一致
公共 HeaderX-Request-IDX-TimestampX-NonceX-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 / CPCCPC → FCC
身份 HeaderX-SNX-Fitron-Client-Id
密钥SN_Secret(出厂烧录)FitronClientSecret(部署时线下交付)
签名原文uppercase(SN):TIMESTAMP:NONCE:BODYuppercase(ClientId):TIMESTAMP:NONCE:BODY
公共 Header完全一致完全一致

HTTPS 请求头

工控机请求头(IPC → FCC / CPC)

Header必填说明
Content-Typeapplication/json
X-SN设备序列号
X-Request-IDUUID v4,日志追踪与幂等去重(推荐携带)
X-TimestampUnix 秒级时间戳
X-Nonce32 位随机 hex
X-SignatureHMAC-SHA256 签名

CPC 请求头(CPC → FCC)

Header必填说明
Content-Typeapplication/json
X-Fitron-Client-IdCPC 客户端标识
X-Request-IDUUID v4,日志追踪与幂等去重(推荐携带)
X-TimestampUnix 秒级时间戳
X-Nonce32 位随机 hex
X-SignatureHMAC-SHA256 签名

HTTP 请求结构(统一约定)

所有 IPC -> Backend 的 POST 请求都拆为两部分:

  1. Header:身份与安全信息(X-SNX-Request-IDX-TimestampX-NonceX-Signature
  2. Body:业务数据(控制结果、扫脸数据、补偿记录等)

Header 与 Body 字段去重规则

  • Header 中已有的字段,Body 可以不重复携带(推荐不重复)
  • 业务端以 Header 为准进行身份识别与验签
  • 若 Body 中仍带了同名字段(如 sntimestamp),则必须与 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 Port8883
ClientID{ProductID}.{SN}
Username{ProductID}{SN};120101;{ConnId};{Expiry}
PasswordBase64(HMAC-SHA256(DeviceSecret, Username))
KeepAlive60 秒
CleanSessiontrue

TLS 与密钥存储

  • HTTPS 与 MQTT 均使用 TLS 1.2+
  • config_url 仅允许 HTTPS
  • SN_Secret / DeviceSecret 禁止明文落盘
  • 出厂预置密钥仅用于首次注册场景,注册完成后应可擦除

安全待确认项

  • 首次注册是否全部使用出厂预置密钥,还是统一直接烧录 SN_Secret
  • IPC 端密钥存储是否要求 TEE 或硬件安全模块
  • Nonce 记录采用 Redis 还是数据库兜底

飞创 Fitron 内部规划文档