2. BLE协议基础回顾:BLE协议栈架构、GATT与GAP角色、配对与绑定机制、ATT层安全属性
好,咱们正式开始聊 BLE 配网安全之前,得先把地基打牢。BLE 协议栈这东西,说白了就是一套分层的通信规则。我刚开始啃 BLE 的时候,也被那几层结构绕得头晕。后来做项目踩了坑才明白——不理解协议栈,你根本不知道安全漏洞会从哪一层钻进来。
这一节我会带着大家把 BLE 协议栈的核心骨架捋一遍。重点放在跟安全强相关的部分:GATT/GAP 角色、配对绑定、还有 ATT 层的安全属性。嗯,咱们不搞教科书式的罗列,我会穿插一些实际项目里的教训。
2.1 BLE协议栈架构:Controller、Host、Application
BLE 协议栈分三层:Controller(控制器)、Host(主机)、Application(应用)。
Controller 管物理层和链路层,说白了就是负责发信号、收信号、跳频这些底层活。Host 管逻辑链路控制和适配协议(L2CAP)、安全管理(SM)、属性协议(ATT)、通用属性协议(GATT)这些。Application 就是咱们写业务逻辑的地方。
我见过不少工程师把安全逻辑全堆在 Application 层,觉得底层不用管。结果呢?中间人攻击一来,数据在 Host 层就被截了。所以我的习惯是:安全必须贯穿三层。
关键点:Controller 和 Host 之间通过 HCI(Host Controller Interface)通信。HCI 本身也可能成为攻击面——如果你用 UART 做 HCI,线缆暴露在外,攻击者可以直接监听。
下面这张图是我自己画的 BLE 协议栈分层结构,方便大家对照着看:
2.2 GATT 与 GAP 角色
GAP(Generic Access Profile)管的是设备怎么被发现、怎么建立连接。GATT(Generic Attribute Profile)管的是连接之后怎么读写数据。
你想想看,配网场景里:手机要发现设备,这是 GAP 的事;手机要写入 WiFi SSID 和密码,这是 GATT 的事。两个角色缺一不可。
GAP 角色
- Broadcaster:只发广播,不连。比如 Beacon。
- Observer:只收广播,不连。
- Peripheral:从设备,发广播,等待连接。配网设备通常是这个角色。
- Central:主设备,扫描并发起连接。手机通常是这个角色。
我的经验:配网时,设备作为 Peripheral,广播包里不要放敏感信息。我曾经见过有人把 WiFi 密码直接塞广播数据里——嗯,那等于把钥匙挂在大门上。
GATT 角色
- Server:提供数据(Service、Characteristic)。配网设备通常是 Server。
- Client:读写 Server 的数据。手机通常是 Client。
GATT 的数据模型是:Service → Characteristic → Descriptor。每个 Characteristic 有 UUID、属性(读/写/通知/指示)、还有安全权限。
| GATT 元素 | 说明 | 配网中的用途 |
|---|---|---|
| Service | 一组功能的集合 | WiFi 配网服务(自定义 UUID) |
| Characteristic | 具体的数据点 | SSID 特征、密码特征、状态特征 |
| Descriptor | 特征的配置信息 | 客户端特征配置(CCCD) |
2.3 配对与绑定机制
配对(Pairing)是建立安全连接的过程。绑定(Bonding)是把配对信息存下来,下次重连不用再配一次。
BLE 配对分三个阶段:
- 配对特征交换:双方交换 IO 能力、认证要求、密钥大小。
- 短期密钥(STK)生成:用 Just Works、Passkey Entry、或 OOB 方式生成 STK。
- 传输特定密钥:用 STK 加密通道,分发长期密钥(LTK)、身份解析密钥(IRK)、连接签名解析密钥(CSRK)。
避坑指南:Just Works 配对方式不提供中间人攻击(MITM)保护。我曾经在一个智能锁项目里看到产品用了 Just Works,结果测试时用一块 nRF52840 DK 就能模拟手机完成配对——这太危险了。配网场景,我建议至少用 Passkey Entry 或 OOB。
配对方式对比:
| 配对方式 | MITM 保护 | 适用场景 | 我的建议 |
|---|---|---|---|
| Just Works | 无 | 低安全需求 | ❌ 不推荐配网 |
| Passkey Entry | 有 | 有显示屏/键盘的设备 | ✅ 推荐 |
| OOB(Out of Band) | 有 | 有 NFC/二维码等带外通道 | ✅ 强烈推荐 |
| Numeric Comparison | 有 | 双方都有显示屏 | ✅ 可用 |
2.4 ATT 层安全属性
ATT(Attribute Protocol)是 GATT 的底层传输协议。每个 ATT 属性都有安全属性,包括:
- 读权限:是否需要加密、是否需要认证、是否需要授权。
- 写权限:同上。
- 加密要求:数据在传输时是否必须加密。
- 认证要求:是否必须经过配对认证。
说白了,ATT 安全属性就是给每个数据点贴标签:谁能读、谁能写、要不要加密、要不要认证。
核心原则:配网过程中,WiFi 密码所在的 Characteristic 必须设置 加密写 权限。如果设成 无安全写,攻击者在连接建立后可以直接写入恶意数据——我见过不止一个产品犯这个错。
ATT 安全属性在代码中的配置示例(以 Zephyr 为例):
// 定义 WiFi 密码特征,要求加密写
BT_GATT_CHARACTERISTIC(&wifi_password_uuid,
BT_GATT_CHRC_WRITE,
BT_GATT_PERM_WRITE_ENCRYPT,
NULL,
on_password_write,
NULL);
注意看 BT_GATT_PERM_WRITE_ENCRYPT 这个标志。它告诉协议栈:写这个特征之前,必须先建立加密连接。如果没有配对,写入请求会被直接拒绝。
嗯,这里还要提一句:ATT 安全属性是在 Host 层强制执行的。也就是说,即使 Application 层代码写错了,Host 层也会帮你拦住未加密的访问。这就是分层设计的好处——安全底线由底层兜着。
小技巧:调试时可以用 bt_gatt_get_perm() 检查当前特征的权限设置。我习惯在初始化后打印所有特征的权限,确保没有遗漏。