第3章:Join过程安全:OTAA与ABP入网流程、Join-Request/Join-Accept消息加密

好,咱们今天聊聊LoRaWAN入网这件事。说白了,就是设备怎么跟网络服务器“对上暗号”。

我个人习惯把入网方式分成两种:一种是每次上线都重新“握手”的OTAA,另一种是出厂就写好“通行证”的ABP。这两种方式的安全等级,说实话,差得挺远。

3.1 OTAA:动态入网,安全首选

OTAA的全称是Over-The-Air Activation。我建议你在条件允许的情况下,优先用这个方式。为什么?因为它每次入网都会生成新的会话密钥。

流程其实不复杂,就三步:

  1. 终端设备发送Join-Request
  2. 网络服务器验证后回复Join-Accept
  3. 双方派生会话密钥,开始通信

嗯,这里要注意一个细节:Join-Request消息本身是不加密的。你可能会问:“那安全怎么保证?”别急,往下看。

3.1.1 Join-Request消息结构

Join-Request里包含四个字段:

字段 长度 说明
AppEUI 8字节 应用标识符,相当于应用ID
DevEUI 8字节 设备标识符,全球唯一
DevNonce 2字节 随机数,防重放攻击的关键
MIC 4字节 消息完整性校验码

DevNonce这个字段,我在项目里吃过亏。有一次客户反馈设备老是入网失败,查了半天发现是DevNonce重复了。原来他们用的随机数生成器质量太差,2字节的随机数居然在短时间内重复了。

避坑指南:我曾经遇到过设备因为DevNonce重复被网络服务器拒绝入网的情况。记住,每个DevNonce只能用一次,服务器会记录所有用过的值。重复了就拉黑,没商量。

3.1.2 Join-Accept消息加密

Join-Accept是网络服务器对设备的回应。这条消息是加密的,用的密钥是AppKey。AppKey是设备出厂时预置的,只有设备和网络服务器知道。

加密过程是这样的:

  • 使用AES-128解密算法(你没看错,是解密算法)
  • 密钥:AppKey
  • 明文内容:AppNonce + NetID + DevAddr + DLSettings + RxDelay + CFList

为什么加密用解密算法?这是LoRaWAN设计上的一个“小聪明”。因为Join-Accept是服务器发给设备的,设备端用AppKey做AES解密就能得到明文。而攻击者没有AppKey,就算截获了也解不开。

个人经验:我刚开始做LoRaWAN时,看到“加密用解密算法”这个设计也觉得奇怪。后来想明白了——这其实是为了减少设备端的计算量。终端设备资源有限,能省一点是一点。

3.2 ABP:静态入网,方便但有风险

ABP(Activation By Personalization)就简单多了。设备出厂时,直接把会话密钥写死在固件里。每次上电就能直接发数据,不需要入网流程。

听起来很方便对吧?但代价是安全性的下降。

3.2.1 ABP的安全隐患

我总结了一下,ABP主要有三个问题:

  • 密钥泄露风险:会话密钥存储在设备中,一旦被读取,整个网络都受影响
  • 重放攻击:没有DevNonce机制,攻击者可以重放旧消息
  • 密钥更新困难:要换密钥?得重新烧录固件

说实话,我在实际项目中很少用ABP。除非是那种对安全性要求不高、设备数量又特别大的场景,比如简单的温湿度监测。

3.3 会话密钥派生机制

不管是OTAA还是ABP,最终都要生成两个会话密钥:

  • NwkSKey:网络会话密钥,用于MAC层加密和完整性校验
  • AppSKey:应用会话密钥,用于应用层数据加密

OTAA方式下,这两个密钥是这样派生的:

NwkSKey = aes128_encrypt(AppKey, 0x01 | AppNonce | NetID | DevNonce | pad16)
AppSKey = aes128_encrypt(AppKey, 0x02 | AppNonce | NetID | DevNonce | pad16)

你看,区别就在第一个字节:0x01和0x02。这样设计的好处是,即使一个密钥被破解,另一个还是安全的。

关键点:NwkSKey和AppSKey是分开的。网络服务器只知道NwkSKey,应用服务器只知道AppSKey。这种“职责分离”的设计,能有效防止内部人员滥用权限。

3.4 两种入网方式对比

对比项 OTAA ABP
入网流程 需要Join-Request/Accept 直接通信
密钥生成 每次入网动态生成 出厂固定
防重放 有DevNonce机制 无
密钥更新 重新入网即可 需重新烧录
适用场景 大多数场景 低安全需求、大规模部署

我个人建议,除非有特殊原因,否则都用OTAA。虽然入网过程多花几秒钟,但换来的是更高的安全性。

3.5 核心流程可视化

下面这张图展示了OTAA入网的完整流程,包括消息交换和密钥派生过程:

OTAA入网流程与密钥派生 终端设备 网络服务器 应用服务器 ① Join-Request (AppEUI+DevEUI+DevNonce+MIC) ② Join-Accept (加密: AppKey AES解密) 密钥派生 NwkSKey = AES(AppKey, 0x01|...) AppSKey = AES(AppKey, 0x02|...) ③ 加密数据通信 (NwkSKey + AppSKey) AppSKey解密 ⚠ 注意: Join-Request不加密,但MIC防篡改 Join-Accept用AppKey加密,防窃听

从这张图可以清楚看到,整个入网过程的核心就是“先验证身份,再派生密钥”。设备用AppKey证明自己是合法的,服务器才放心地把会话密钥交出来。

3.6 实际部署建议

最后,分享几个我在实际项目中的经验:

  • DevNonce管理:确保每次入网都生成不同的随机数,建议用硬件随机数发生器
  • AppKey存储:如果设备支持安全元件(SE),一定要把AppKey存进去
  • 入网失败处理:设备入网失败后,建议等待随机时间再重试,避免“雪崩效应”
  • ABP慎用:除非你确定攻击者无法物理接触设备,否则别用ABP

嗯,关于入网安全,今天就聊这么多。记住一句话:入网是安全的第一道门,门没锁好,后面做再多加密都是白搭。