物联网设备的 OTA(Over-the-Air)更新与资源访问面临独特挑战:设备资源受限(RAM/Flash 以 KB 计)、网络连接间歇性、以及无法依赖持续在线的 PKI 基础设施。传统的 OAuth 或长有效期 API 密钥方案在嵌入式场景下显得笨重且不安全。Signy—— 由 Golioth 开源的轻量级签名 URL 库 —— 提供了一种使用非对称加密在设备端生成带时间窗的访问 URL 的方案,但将其应用于生产环境仍需解决吊销机制与离线验证两大核心问题。
Signy 协议结构与基础约束
Signy 基于 ARM 的 PSA Cryptography API 构建,其生成的签名 URL 遵循标准格式:BASEURL?nb=NOTBEFORE&na=NOTAFTER&cert=CERTIFICATE&sig=SIGNATURE。其中NOTBEFORE与NOTAFTER构成有效期窗口(通常配置为分钟级),CERTIFICATE为设备证书(Base64 URL 无填充编码),SIGNATURE则是对 URL 前缀的签名。服务器验证时只需校验证书链、时间窗与签名有效性即可授权访问。
该设计的关键特性在于 "无状态"—— 服务器无需维护会话或 Token 存储,仅需信任设备证书与根 CA。然而,这种无状态性也带来了吊销难题:一旦 URL 签发,在NOTAFTER时间到达前,服务器无法单方面使其失效。若设备私钥泄露或证书被撤销,已签发的 URL 在过期前仍可能被恶意使用。
轻量级吊销策略设计
针对嵌入式场景,有效的吊销策略需平衡实时性与资源开销。我们提出三层防护模型:
第一层:时间窗压缩。将CONFIG_SIGNY_URL_VALIDITY_DURATION配置为 5-15 分钟(而非小时或天),限制泄露 URL 的攻击窗口。虽然设备需要相对准确的时间源(NTP 或蜂窝网络时间),但短 TTL 能显著降低风险敞口。若设备时钟偏差较大,可结合设备端的NOTBEFORE偏移量容忍参数(如 ±2 分钟)避免合法请求被拒绝。
第二层:PSA 密钥轮换。利用 PSA Crypto API 的持久化密钥槽实现无缝轮换。采用双槽位设计:KEY_SLOT_ACTIVE(当前活跃密钥)与KEY_SLOT_NEXT(下一轮换密钥)。轮换流程如下:服务器通过已认证的安全通道(如 LwM2M Bootstrap 或 TLS 双向认证)下发新证书与私钥,设备将其导入KEY_SLOT_NEXT;验证新密钥可正常签发 URL 后,原子切换活跃槽位指针;延迟一个 TTL 周期后,安全销毁旧密钥。此过程无需重启设备,且旧 URL 在 TTL 到期后自然失效。
第三层:应用层硬吊销。对于必须立即阻断的紧急情况(如固件版本发现严重漏洞),纯依赖时间窗与密钥轮换无法满足需求。此时需在资源服务器前增加一层轻量级检查:维护一个 "被撤销资源哈希列表"(Revocation List),在设备请求下载时,先校验资源哈希是否命中黑名单,再执行签名验证。该列表可通过 CDN 边缘缓存或设备本地缓存实现,平衡实时性与查询开销。
离线验证的设备端实现
签名 URL 解决的是 "谁能访问"(授权),而非 "内容是否可信"(完整性)。在设备可能离线(无网络连接验证 OCSP 或 CRL)的场景下,必须建立设备端的密码学信任链。
根信任锚定:在设备出厂或首次配网时,将厂商根公钥(或根 CA 证书)烧录至受保护的存储区域(如安全元件、OTP Flash 或 PSA Internal Trusted Storage)。该公钥永不通过网络更新,仅在物理安全环境下通过本地接口(UART、JTAG)替换。
签名清单验证:OTA 包应采用 "清单 + 有效载荷" 结构。清单为 CBOR 或 JSON 格式,包含:固件版本号(单调递增)、目标设备型号、SHA-256/384 哈希、签名算法标识、以及清单本身的 ECDSA/RSA-PSS 签名。设备下载固件后,首先使用根公钥验证清单签名,再计算下载内容的哈希与清单比对。此过程完全离线,不依赖签名 URL 的有效性或网络连接状态。
版本回滚防护:清单中应包含min_version字段,设备固件在更新前检查新版本是否大于当前版本,防止恶意降级攻击。Bootloader 需在启动阶段再次执行相同的签名与哈希验证,形成 "下载 - 验证 - 启动 - 二次验证" 的双保险。
可落地的参数与监控清单
部署 Signy 协议的嵌入式系统,建议采用以下参数配置:
| 参数项 | 建议值 | 说明 |
|---|---|---|
| URL 有效期 | 5-10 分钟 | 平衡性能开销与安全窗口 |
| 密钥轮换周期 | 30-90 天 | 或按证书有效期 1/4 计算 |
| 时钟容差 | ±2 分钟 | 应对 NTP 同步偏差 |
| 清单签名算法 | ECDSA P-256 | PSA 原生支持,128 位安全强度 |
| 固件哈希算法 | SHA-256 | 与 PSA Crypto API 兼容 |
监控要点包括:密钥轮换成功率、URL 验证失败率(区分时间窗失效与签名错误)、离线验证失败次数(可能指示固件篡改尝试)、以及吊销列表查询延迟。若发现异常失败率激增,应触发告警并考虑强制轮换密钥或更新吊销列表。
资料来源
- Golioth Signed URLs 文档: https://docs.golioth.io/connectivity/credentials/signed-urls/
- Signy GitHub 仓库: https://github.com/golioth/signy