4、GATT安全机制:配对与绑定、加密与认证、安全等级(MITM、LESC)、ATT权限与属性权限

蓝牙GATT的安全,说白了就是解决三个问题:你是谁、数据有没有被偷看、消息有没有被篡改。很多开发者把注意力全放在服务设计和UUID分配上,结果产品一上线就被抓包工具秒破——嗯,这种事我见过不止一次。

这一章我们就把GATT安全机制的底裤扒干净。从配对绑定到加密认证,再到那些让人头大的安全等级和权限位,我会把每个坑都指给你看。

4.1 配对与绑定:建立信任的第一步

配对(Pairing)和绑定(Bonding)是两个容易混淆的概念。我习惯这么记:配对是过程,绑定是结果。

  • 配对:两个蓝牙设备临时交换身份信息,建立加密连接的过程。
  • 绑定:配对完成后,双方把对方的身份信息(Long Term Key,简称LTK)存下来。下次连接直接复用,不用再走一遍配对流程。

配对流程分三个阶段:

  1. 配对特征交换:双方互相告诉对方自己支持什么IO能力、有没有OOB数据、要不要绑定。
  2. 短期密钥(STK)生成:根据双方能力协商出一个临时密钥,用来加密当前连接。
  3. 传输特定密钥分发:把LTK、IRK、CSRK等长期密钥分发给对方。这一步只有绑定模式下才会做。

关键点:如果只配对不绑定,每次断开重连都要重新走一遍配对流程。这在耳机、手环这类频繁重连的设备上体验极差。所以消费类产品几乎都做绑定。

我在项目中遇到过一个问题:某款智能锁和手机配对后,手机换了APP再连就提示“设备已被绑定”。查了半天才发现是绑定信息没做清除接口——用户换手机就废了。所以绑定信息的管理接口一定要留,别做死。

4.2 加密与认证:数据安全的双保险

加密(Encryption)和认证(Authentication)是两回事,但经常被混为一谈。

  • 加密:保证数据在传输过程中不被偷看。用的是AES-CCM加密算法。
  • 认证:保证通信的对方确实是它声称的那个设备。防止中间人攻击(MITM)。

蓝牙4.0到4.1用的是传统安全配对(Legacy Pairing),加密强度一般,而且容易被暴力破解。从蓝牙4.2开始引入了安全连接(Secure Connections,SC),使用ECDH密钥交换和AES-128-CTR加密,安全性上了一个大台阶。

特性 Legacy Pairing Secure Connections
密钥交换算法 基于临时随机数 ECDH(椭圆曲线Diffie-Hellman)
加密算法 AES-CCM 128位 AES-CCM 128位
MITM防护 可选,强度低 强制支持,强度高
密钥长度 固定128位 128位,但熵更高
兼容性 蓝牙4.0/4.1设备 蓝牙4.2+设备

注意:如果你的产品需要兼容蓝牙4.1及以下的旧设备,必须同时支持Legacy和SC两种模式。但建议默认优先使用SC,只有在对方不支持时才回退到Legacy。

4.3 安全等级:MITM与LESC

蓝牙规范定义了四种安全等级,从低到高分别是:

  1. 等级1:无安全(No Security)——不加密,不认证。只适合传输公开数据,比如温度传感器广播。
  2. 等级2:仅加密(Encryption Only)——数据加密传输,但不验证对方身份。能防窃听,防不了中间人。
  3. 等级3:加密+认证(Encryption + Authentication)——加密且验证身份。需要MITM保护。
  4. 等级4:加密+认证+LESC——在等级3基础上,强制使用Secure Connections和128位密钥。这是目前最高的安全等级。

这里重点说一下MITM(中间人攻击)和LESC(低功耗安全连接)。

MITM保护

MITM攻击的场景是这样的:攻击者假装是设备A跟设备B通信,同时又假装是设备B跟设备A通信。两边都被蒙在鼓里。

防止MITM的关键在于带外确认。比如手机和手环配对时,两边都显示一个6位数字,你确认一下数字是否一致——这就是MITM保护。如果攻击者插在中间,两边的数字对不上,配对就会失败。

我曾经帮一个客户排查问题:他们的智能门锁老是配对失败。后来发现是IO能力配置错了——门锁只有LED显示,没有输入按键,但代码里配成了“KeyboardOnly”。结果手机端要求用户输入数字,门锁端却显示不了,两边永远对不上。嗯,IO能力一定要如实配置,别为了省事瞎填。

LESC(低功耗安全连接)

LESC是蓝牙4.2引入的增强安全机制。它使用ECDH密钥交换,生成的密钥强度远高于Legacy模式。而且LESC强制要求MITM保护,不能跳过。

LESC的配对确认方式有两种:

  • Numeric Comparison:两边显示一个6位数字,用户确认一致。适合双方都有显示屏和确认按钮的设备。
  • Passkey Entry:一方显示数字,另一方输入。适合一方有屏、一方有键盘的场景。
  • Out of Band(OOB):通过NFC、二维码等外部通道交换配对信息。安全性最高,但实现也最复杂。

我的建议:如果产品面向消费市场,优先用Numeric Comparison。用户操作简单,安全性也够。Passkey Entry在智能家居场景里很常见——手机输入门锁上显示的数字。OOB虽然安全,但需要额外硬件支持,成本高。

4.4 ATT权限与属性权限

安全机制最终要落地到具体的属性(Attribute)上。GATT协议里,每个属性都有权限位,用来控制谁能读、谁能写、什么条件下能操作。

属性权限分三类:

  • 访问权限(Access Permissions):读、写、读写、不可访问。
  • 加密权限(Encryption Permissions):是否需要加密连接才能访问。
  • 认证权限(Authentication Permissions):是否需要配对认证才能访问。
  • 授权权限(Authorization Permissions):是否需要应用层额外授权(比如用户点击确认)。

这些权限可以组合使用。比如一个心率测量特征值,可以配置为:

// 伪代码示例:心率特征值权限配置
Characteristic heartRateChar;
heartRateChar.uuid = 0x2A37;
heartRateChar.properties = READ | NOTIFY;
heartRateChar.permissions = {
    .read_encrypted = true,      // 读操作需要加密
    .read_authenticated = true,  // 读操作需要认证
    .read_authorized = false,    // 不需要额外授权
    .write_encrypted = false,    // 不允许写
    .write_authenticated = false,
    .write_authorized = false
};

这个配置的意思是:只有经过配对认证且加密连接的设备才能读取心率数据。未配对的设备连读都读不了。

踩坑提醒:我曾经见过一个产品,开发者把“需要加密”和“需要认证”搞混了。结果设备只配了对没绑定,每次重连都要重新配对,用户体验极差。记住:加密是加密,认证是认证,绑定是绑定。三个概念别混用。

4.5 安全机制选择决策树

说了这么多,到底该怎么选?我画了一张图帮你理清思路。

GATT安全机制选择决策树 是否需要安全连接? 等级1:无安全 是否需要加密? 等级2:仅加密 是否需要MITM防护? 等级2:仅加密 是否支持LESC? 等级3:加密+认证 等级4:最高安全 提示:等级越高,配对流程越复杂,用户体验越差。根据产品场景选择合适等级,不要盲目追求最高安全。

4.6 实战建议:安全配置清单

最后,我整理了一份安全配置清单。每次做GATT服务设计时,对着这张表过一遍,基本不会漏。

检查项 说明 常见错误
IO能力配置 如实填写设备的输入输出能力 为了省事填NoInputNoOutput,导致无法做MITM保护
绑定标志位 是否需要存储LTK实现自动重连 忘记设置Bonding标志,每次重连都要配对
属性权限 每个特征值的读写权限是否合理 敏感数据没设加密权限,裸奔在空气中
安全等级选择 根据数据敏感度选择1-4级 所有服务都用最高等级,导致配对慢、功耗高
密钥存储 LTK、IRK等密钥是否安全存储 密钥明文存在Flash里,被读出来就废了
兼容性测试 是否兼容不同蓝牙版本的主机 只测了iOS没测Android,或者反过来

一个小技巧:开发阶段可以把安全等级降到最低,方便抓包调试。但发布前一定要改回来。我曾经见过一个产品,发布固件里忘了改安全配置,结果用户数据全程明文传输——嗯,那个版本被紧急召回重刷了。

GATT安全机制就讲到这里。记住一句话:安全不是功能,是属性。它应该渗透到每个服务、每个特征值、每个属性的设计中去,而不是最后才想起来“哦,我们好像还没做安全”。