4. Join过程

好,咱们接着聊。上一章我们把LoRaWAN的密钥体系拆开了,你知道了NwkSKey、AppSKey、AppKey各自管什么。那这些密钥是怎么装到设备上的?这就引出了入网方式的选择。

说白了,设备要上网,得先和网络服务器“对上暗号”。LoRaWAN给了两条路:OTAA(空中激活)和ABP(预注册激活)。我做了这么多年物联网安全,可以负责任地告诉你——选错路,后面全是坑。

4.1 两条路,两种哲学

先看个直观的对比,你心里就有数了。

对比维度 OTAA(空中激活) ABP(预注册激活)
密钥来源 入网时动态派生 出厂时静态烧录
设备身份 DevEUI(全球唯一) DevAddr(网络内唯一)
入网流程 Join Request → Join Accept 直接发数据
安全性 高(密钥每次更新) 低(密钥固定不变)
适用场景 大多数生产环境 实验室、快速原型

嗯,看到这个表,你可能已经猜到了——OTAA是推荐方式。但别急,ABP也不是一无是处,咱们一个一个说。

4.2 OTAA:真正的“握手”

OTAA的全称是Over-The-Air Activation。你想想看,设备第一次上电,它连自己在哪个网络都不知道,怎么发数据?所以它得先“自我介绍”,然后等服务器给它发“通行证”。

流程其实就两步,但每一步都藏着安全设计。

4.2.1 Join Request:设备在喊“有人吗?”

设备发一条Join Request消息,里面包含:

  • AppEUI:应用标识,告诉服务器“我想加入哪个应用”
  • DevEUI:设备唯一ID,相当于设备的身份证号
  • DevNonce:一个随机数,防止重放攻击

这里有个关键点——DevNonce。我遇到过不止一次,有人把DevNonce写死了。结果呢?服务器收到重复的DevNonce,直接拒绝入网。设备就成了“孤儿”,永远连不上网。

避坑指南:DevNonce必须每次都不一样。LoRaWAN规范要求服务器记录每个设备最近用过的DevNonce列表,重复的就丢弃。我曾经见过一个项目,工程师用系统时间戳的低16位当DevNonce,结果设备重启后时间重置,DevNonce又从头开始……嗯,排查了整整两天。

4.2.2 Join Accept:服务器发“通行证”

服务器收到Join Request后,会做两件事:

  1. 验证DevNonce是否重复
  2. 用AppKey加密生成Join Accept消息

Join Accept里包含最重要的东西——AppNonce。这个随机数会和AppKey一起,派生出NwkSKey和AppSKey。也就是说,每次入网,会话密钥都是全新的。

我个人习惯把这个过程叫做“安全握手”。设备和服务器的AppKey是出厂时预置的,相当于双方都知道一个“秘密”。通过这个秘密,每次见面都换一个新密码。你想想看,就算有人偷听了这次通信,下次入网时密钥已经变了,他拿到的就是一堆废纸。

4.3 ABP:方便,但危险

ABP(Activation By Personalization)就简单粗暴多了。设备出厂时,直接把NwkSKey、AppSKey和DevAddr烧录进去。设备上电后,不用任何握手,直接发数据。

听起来很方便对吧?但代价是什么?

  • 密钥固定:一旦泄露,设备永远不安全
  • 无法更换网络:DevAddr是写死的,换网络就得重新烧录
  • 重放攻击风险:没有Nonce机制,攻击者可以重放旧数据包

我记得有一次帮客户做安全审计,他们用了ABP方式,密钥直接明文存在Flash里。结果呢?设备被物理破解后,密钥被提取,攻击者伪造了上千个“合法”设备,往服务器灌垃圾数据。那叫一个惨。

核心区别:OTAA是“动态安全”,每次入网都换密钥;ABP是“静态安全”,密钥一辈子不变。在物联网世界里,静态就意味着脆弱。

4.4 一张图看懂两种入网方式

下面这张SVG图,把两个流程放在一起对比,你一看就明白。

OTAA与ABP入网流程对比 OTAA vs ABP 入网流程对比 OTAA 空中激活 终端设备 网络服务器 ① Join Request (AppEUI + DevEUI + DevNonce) ② Join Accept (AppNonce + 网络参数) 密钥派生(设备端) NwkSKey = AES(AppKey, AppNonce | ...) AppSKey = AES(AppKey, AppNonce | ...) 后续通信使用动态派生的会话密钥 每次入网密钥不同 ✅ 安全性高 ABP 预注册激活 终端设备 网络服务器 ① 直接发数据 (使用预置NwkSKey加密) 出厂时预置 NwkSKey = 固定值 AppSKey = 固定值 密钥永不变化 一旦泄露,永久不安全 ⚠️ 安全性低

4.5 什么时候用ABP?

说了这么多OTAA的好,那ABP是不是就该被淘汰?也不是。我个人的经验是,ABP在两种场景下还有价值:

  • 快速原型验证:实验室里测功能,不想走完整的入网流程,ABP能省时间
  • 资源极度受限的设备:有些MCU连AES硬件加速都没有,跑OTAA的密钥派生太吃力

但注意——生产环境千万别用ABP。我见过太多人图省事,结果上线后被攻击者抓包破解,整个网络沦陷。嗯,安全这东西,省一步就是给攻击者留一步。

我的建议:除非你有100%的把握保证物理安全(比如设备装在保险柜里),否则一律用OTAA。就算开发阶段,也建议先用OTAA,因为ABP切OTAA的改动量不小,别等到量产了才后悔。

4.6 一个容易被忽略的细节:Join-Request的MIC

你可能注意到了,Join Request消息里没有MIC(消息完整性校验)。为什么?因为这时候设备还没有会话密钥啊!

那怎么防止有人伪造Join Request?答案是——服务器通过DevNonce去重来防重放。但伪造一个合法的Join Request本身是做不到的,因为Join Accept是用AppKey加密的,只有真正的设备才能解密。

这里有个小坑:有些实现会在Join Request里加一个可选的MIC字段,用AppKey计算。但规范里没强制要求。我个人习惯是加上,多一层保护总没坏处。

4.7 小结

OTAA和ABP,说白了就是“动态安全”和“静态安全”的选择。OTAA虽然多了一次握手,但换来的是每次入网都换密钥的安全保障。ABP省了流程,却把安全赌在了密钥不泄露上。

在物联网这个领域,设备数量动辄成千上万,一旦密钥泄露,修复成本高得吓人。所以我的建议很明确:能用OTAA,就别碰ABP。