3. 安全通信:TLS/DTLS 在智能家居中的应用
智能家居设备,说白了就是一群“小电脑”在互相说话。但问题是——它们说的话,别人能听懂吗?
我见过太多案例:智能灯泡被隔壁小孩用手机直接控制,智能门锁的通信被截获后重放攻击。嗯,这就是没做好安全通信的后果。ETSI EN 303 645 里明确要求,设备必须使用 TLS 或 DTLS 来保护通信。今天我们就来拆解这个。
3.1 为什么是 TLS 和 DTLS?
传统 HTTP 是明文传输,就像在明信片上写密码。TLS 就是那个信封。但智能家居里,有些设备是“间歇性联网”的——比如传感器每隔几秒发一次数据,或者门锁只在开锁时通信。这时候,TCP 的握手开销就太大了。
DTLS 就是为这种情况设计的。它基于 UDP,但提供了和 TLS 同等级别的加密和认证。我个人习惯这样选型:
| 场景 | 推荐协议 | 原因 |
|---|---|---|
| 网关与云平台 | TLS 1.2/1.3 | 稳定连接,双向认证 |
| 传感器上报数据 | DTLS 1.2 | 低延迟,无连接维护 |
| 门锁/开关控制 | DTLS 1.2 | 短消息,快速响应 |
| 固件升级 | TLS 1.3 | 大文件传输,0-RTT |
3.2 证书管理——最容易被忽视的环节
TLS 的核心是证书。但智能家居设备不像服务器,它们没有固定 IP,没有域名,甚至没有屏幕来显示证书信息。那怎么管理?
ETSI 标准里给出了三条路:
- 预置证书:出厂时烧录设备证书和 CA 根证书。
- 动态签发:设备首次联网时,通过注册流程向 CA 申请证书。
- 自签名 + 白名单:设备自签证书,云端维护设备公钥白名单。
我个人最推荐第二种。为什么?因为预置证书一旦泄露,整批设备都得召回。我在一个智能门锁项目里就遇到过——工厂烧录时证书模板被泄露,结果市面上出现了大量“克隆锁”。
3.3 密钥存储——安全通信的最后一道防线
证书和私钥存哪里?这问题看似简单,但 90% 的安全事件都出在这里。
ETSI 标准要求:私钥必须防提取、防篡改、防侧信道攻击。具体来说:
- 安全元件(SE):独立芯片,专门存密钥。成本高,但最安全。
- TEE(可信执行环境):在主芯片内划出一块安全区域。性价比高。
- 软件加密存储:用设备唯一密钥加密后存 Flash。成本最低,但风险也最高。
我建议:至少做到 TEE 级别。如果成本实在敏感,那也要用芯片自带的唯一 ID 作为密钥派生因子,绝不能直接存明文。
3.4 核心流程:TLS/DTLS 握手与证书验证
我们来看一个典型的智能家居设备与云平台建立 TLS 连接的过程。我用一个流程图来展示:
这个流程里,最容易出问题的是第③步——证书验证。很多设备只检查了证书是否过期,却没验证证书链的完整性。我见过一个智能摄像头,它只检查了服务器证书的 Common Name,结果被中间人攻击轻松绕过。
3.5 代码示例:ESP32 上的 TLS 客户端
我们来看一个实际代码。这是 ESP32 上使用 mbedTLS 库建立 TLS 连接的简化实现:
#include <mbedtls/net_sockets.h>
#include <mbedtls/ssl.h>
#include <mbedtls/entropy.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/x509_crt.h>
// 初始化 SSL 上下文
mbedtls_ssl_context ssl;
mbedtls_ssl_config conf;
mbedtls_x509_crt cacert;
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
void tls_client_init(void) {
// 1. 加载 CA 证书
mbedtls_x509_crt_init(&cacert);
mbedtls_x509_crt_parse(&cacert, ca_cert_pem, strlen(ca_cert_pem) + 1);
// 2. 配置 TLS
mbedtls_ssl_config_init(&conf);
mbedtls_ssl_config_defaults(&conf,
MBEDTLS_SSL_IS_CLIENT,
MBEDTLS_SSL_TRANSPORT_STREAM,
MBEDTLS_SSL_PRESET_DEFAULT);
// 3. 设置证书验证
mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_REQUIRED);
mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL);
// 4. 设置随机数生成器
mbedtls_entropy_init(&entropy);
mbedtls_ctr_drbg_init(&ctr_drbg);
mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func,
&entropy, NULL, 0);
mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
// 5. 建立连接
mbedtls_ssl_init(&ssl);
mbedtls_ssl_setup(&ssl, &conf);
mbedtls_ssl_set_hostname(&ssl, "cloud.smarthome.com");
// 6. 握手
int ret = mbedtls_ssl_handshake(&ssl);
if (ret != 0) {
// 处理握手失败
ESP_LOGE("TLS", "Handshake failed: %d", ret);
return;
}
// 7. 验证证书
uint32_t flags = mbedtls_ssl_get_verify_result(&ssl);
if (flags != 0) {
ESP_LOGE("TLS", "Certificate verification failed: %lu", flags);
return;
}
ESP_LOGI("TLS", "TLS connection established successfully");
}
MBEDTLS_SSL_VERIFY_REQUIRED 改成了 MBEDTLS_SSL_VERIFY_OPTIONAL,结果证书验证失败时连接依然建立。这是严重的安全漏洞。
3.6 性能优化与资源受限设备
智能家居设备很多是资源受限的——几 MB 的 Flash,几十 KB 的 RAM。TLS 握手开销不小。怎么优化?
- 会话复用:保存 Session ID 或 Session Ticket,下次握手直接恢复。
- PSK 模式:预共享密钥模式,省去证书交换。适合设备与网关之间。
- 精简证书链:只保留必要的中间 CA,减少握手数据量。
- 硬件加速:使用芯片的 AES/ECC 硬件引擎,软件实现太慢。
我在一个温控器项目里,把 TLS 握手时间从 3.2 秒降到了 0.8 秒。怎么做的?用了会话复用 + 硬件 ECC 加速。嗯,效果立竿见影。
- 必须使用 TLS 1.2 或更高版本(DTLS 1.2 或更高)
- 必须支持双向认证(设备证书 + 服务器证书)
- 私钥必须存储在安全硬件中
- 必须支持证书吊销检查
- 必须使用前向安全密码套件(ECDHE 或 DHE)
好了,安全通信这块就拆解到这里。记住:TLS/DTLS 不是装上去就完事了,证书管理和密钥存储才是真正的考验。下次你看到某个智能设备说“支持 TLS 加密”,不妨多问一句——你的私钥存哪了?