4. DTLS在CoAP中的角色:DTLS如何保护CoAP、安全模式对比

好,咱们进入第4章。这一章我打算把DTLS在CoAP里的位置彻底讲透。很多初学者容易把CoAP和DTLS割裂开看,觉得DTLS就是个“加个锁”的步骤。其实不是这样。DTLS和CoAP的关系,更像是信封和信纸——没有信封,信纸上的内容谁都能看。

我在做智能照明项目时,就遇到过客户问:“CoAP本身不是有重传机制吗?为什么还要DTLS?”嗯,这个问题问到了点子上。CoAP的重传只保证消息到达,不保证消息不被篡改或偷看。说白了,CoAP管“能不能送到”,DTLS管“送的是不是原样、有没有被偷看”。

4.1 DTLS在CoAP协议栈中的位置

先看一张图,你就明白DTLS插在哪儿了。

CoAP + DTLS 协议栈分层 应用层(传感器数据/控制指令) CoAP(请求/响应模型) DTLS(加密/认证/完整性) UDP(无连接传输) IP(网络层) 数据流向 DTLS 对 CoAP 消息 整体加密,不解析内部 握手阶段协商密钥 和加密套件

你看,DTLS 夹在 CoAP 和 UDP 之间。这意味着什么?CoAP 把消息交给 DTLS,DTLS 加密后再交给 UDP 发送。反过来,UDP 收到数据先交给 DTLS 解密,验证通过后才交给 CoAP 处理。

我个人习惯把 DTLS 比作一个安检通道。CoAP 消息进去之前是明文,出来之后就是密文。接收端那边,密文进去,验证通过后还原成明文。整个过程对 CoAP 上层是透明的——你写 CoAP 代码时根本感觉不到 DTLS 的存在。

4.2 DTLS 如何保护 CoAP 消息

DTLS 给 CoAP 提供了三层保护,我一个个说。

4.2.1 机密性(Confidentiality)

说白了就是加密。CoAP 的请求和响应内容,比如温度传感器的读数、开关指令,在网络上传输时都是密文。我在做智能门锁项目时,曾经抓包看过未加密的 CoAP 消息——开门指令的 URI 路径和 payload 清清楚楚。如果被中间人截获,直接就能开门。加了 DTLS 后,抓包看到的全是乱码。

4.2.2 完整性(Integrity)

保证消息在传输过程中没有被篡改。DTLS 会给每条消息附加一个消息认证码(MAC)。接收端收到后重新计算 MAC,如果对不上,说明消息被改过,直接丢弃。我曾经在测试环境中故意修改了一个 DTLS 加密包的一个字节,结果接收端直接报错,不会把篡改后的数据交给 CoAP。

4.2.3 身份认证(Authentication)

确认通信双方的身份。DTLS 握手阶段会交换证书或预共享密钥,确保你连接的是真正的服务器,而不是伪装的中间人。这一点在固件升级场景特别重要——你肯定不希望设备从恶意服务器下载带后门的固件。

我的经验: 很多开发者只关注加密,忽略了认证。其实认证才是第一道防线。没有认证的加密,就像你把钥匙给了陌生人——他照样能开门。

4.3 四种安全模式对比

CoAP 规范(RFC 7252)定义了四种安全模式。我整理了一张表,方便你对比。

安全模式 认证方式 密钥管理 计算开销 适用场景
NoSec 无 无 无 内网调试、非敏感数据
PreSharedKey 预共享密钥 手动配置 低 资源受限设备、小规模部署
RawPublicKey 非对称密钥对 公钥指纹交换 中 中等规模、无PKI基础设施
Certificate X.509证书链 CA签发 高 大规模部署、需要可扩展性

4.3.1 NoSec 模式

这个模式其实就是裸奔。CoAP 直接跑在 UDP 上,没有任何安全保护。我建议只在以下情况使用:

  • 本地局域网调试,抓包分析协议行为
  • 传感器数据不敏感,比如室内温度采集
  • 网络环境完全可控,比如设备间通过有线连接

但要注意,生产环境千万别用 NoSec。我在一个客户现场见过他们把智能电表的数据用 NoSec 传到公网服务器,结果被第三方抓包看到了用电规律——这其实已经涉及隐私泄露了。

4.3.2 PreSharedKey(PSK)模式

PSK 模式使用对称密钥。通信双方预先配置好相同的密钥,DTLS 握手时用这个密钥进行身份认证和生成会话密钥。

优点很明显:计算开销小,适合单片机、Zigbee 模块这类资源受限设备。缺点也很突出:密钥分发困难。你想想看,如果有 1000 台设备,每台都要手动烧录密钥,生产管理就是个噩梦。

避坑指南: 我曾经在一个项目中,所有设备使用相同的 PSK 密钥。结果一台设备被破解,整个网络的安全防线就全垮了。建议每台设备使用独立的 PSK,或者至少按批次分组。

PSK 模式的 DTLS 握手流程大致如下:

Client Hello  ——>  包含PSK身份提示
                <——  Server Hello + ServerKeyExchange
ClientKeyExchange ——>  包含PSK身份
                <——  ChangeCipherSpec + Finished
ChangeCipherSpec ——>
Finished         ——>
[加密通信开始]

4.3.3 RawPublicKey(RPK)模式

RPK 模式使用非对称密钥对。每个设备有自己的公钥和私钥,通信时交换公钥(或者公钥的哈希值)进行认证。

相比 PSK,RPK 的好处是不需要预先共享密钥,密钥管理更灵活。但计算开销比 PSK 大,因为涉及非对称加密运算。我记得在 ARM Cortex-M4 上做 RPK 握手,一次完整的 ECDHE 密钥交换大概需要几百毫秒——对于实时性要求高的场景,这个延迟需要考虑。

RPK 的典型配置方式:

// 生成密钥对(以mbedTLS为例)
mbedtls_pk_context key;
mbedtls_pk_init(&key);
mbedtls_pk_setup(&key, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY));
mbedtls_ecp_gen_key(MBEDTLS_ECP_DP_SECP256R1,
                    mbedtls_pk_ec(key),
                    mbedtls_ctr_drbg_random,
                    &ctr_drbg);

// 提取公钥指纹(SHA-256哈希)
uint8_t fingerprint[32];
mbedtls_sha256(public_key_der, public_key_len, fingerprint, 0);

4.3.4 Certificate 模式

这是最完整的 DTLS 安全模式。使用X.509 证书链进行身份认证,证书由证书颁发机构(CA)签发。

Certificate 模式的优势在于可扩展性。新设备加入网络时,只要持有 CA 签发的证书,就能自动完成认证。不需要像 PSK 那样手动配置密钥,也不需要像 RPK 那样交换公钥指纹。

但代价也很明显:

  • 证书管理需要 PKI 基础设施
  • 握手过程更复杂,需要验证证书链
  • 内存占用大,证书和私钥可能占用几十 KB

我在一个智慧城市项目中部署了 Certificate 模式,管理 10 万+ 设备。说实话,前期搭建 CA 和证书签发系统花了不少功夫,但后期设备入网完全是自动化的,省了很多运维成本。

4.4 如何选择安全模式

我一般按照这个思路来选择:

  1. 先问自己:数据敏感吗? 不敏感且在内网,NoSec 就够了。
  2. 设备资源够吗? 内存小于 64KB、CPU 主频低于 100MHz,优先考虑 PSK。
  3. 设备数量多少? 少于 100 台,PSK 或 RPK 都行;超过 1000 台,建议上 Certificate。
  4. 有没有 PKI 基础设施? 没有的话,RPK 是 Certificate 的轻量替代方案。
我的建议: 如果你刚开始做 CoAP 安全,从 PSK 模式入手最稳妥。配置简单,踩坑少。等把 DTLS 握手流程跑通了,再升级到 RPK 或 Certificate。别一上来就搞证书链——我见过太多人在证书验证环节卡壳,最后连基本通信都跑不通。