03-帧计数器与重放防线


4.3 帧计数器与重放防线

本节摘要:LoRaWAN 用 32 位帧计数器防重放:设备与网络服务器各维护一套,帧计数倒退或异常跳跃即丢弃。本节讲清计数器语义、回绕处理与网络侧的同步算法。位置:4.2 讲了加密与 MIC,本节补上"重放"这道防线——MIC 管完整性,帧计数管新鲜度。

计数器语义:两套,分方向

LoRaWAN 1.0.x 维护两套 32 位计数器:FCntUp(设备侧递增,校验上行)与 FCntDown(网络服务器侧递增,校验下行)。1.1 起拆分更细(NFCntUp/Down、AFCntUp/Down),但原则一致:每个方向一个单调递增计数器,接收方拒绝"倒退"的帧。

帧里只携带 16 位(FCnt 字段),完整 32 位在接收端维护:

接收端算法(以上行为例): 1. 收到帧,取其 16 位 FCnt 与 DevAddr 2. 与本地记录的完整 FCntUp 比对:若 16 位值 + 高 16 位推断 ≈ 本地值 + 1,则正常 3. 若推断值 ≤ 本地值 → 疑似重放,丢弃;若推断值 > 本地值 + 允许的跳变窗口 → 计数跳跃异常 4. 正常则更新本地值,并处理窗口同步 ​

"允许的跳变窗口"通常取 16384(2^14):设备侧计数器可能因断电回退或 ADR 重置发生小幅跳变,网络服务器在窗口内接受并重新同步,超出则要求设备重新入网。

回绕与重置的两个经典坑

回绕:32 位计数器到 0xFFFFFFFF 后回到 0。协议要求设备在接近回绕时(例如到 0xFFFFFFF0 附近)触发重新入网,网络服务器实现也要在检测到"接近回绕"时主动要求设备重入网——否则回绕后新旧帧计数无法区分。重置:设备断电重启后计数器从 Flash 恢复;若 Flash 未持久化导致计数回退,设备会发"倒退"的帧被网络服务器拒收,表现就是"设备重启后通信全部失败"——正确做法是计数器持久化到 NVM,且入网后由网络服务器把计数同步到设备。

重放攻击的一个完整推演

攻击者截获一个上行帧(含有效 MIC),在网络里反复重放。没有帧计数检查时,每一条都会被处理;有帧计数检查时,只有第一条通过,后续重复帧因计数不递增被丢弃——网络服务器侧对"重复帧"有明确处置:不处理、不下发 ACK。下行同理:设备收到计数倒退的下行帧直接丢弃,防止攻击者回放历史下行指令(如"阀门关闭"指令)。

网络服务器侧的计数同步算法

网络服务器同时服务大量设备,计数器同步是并发敏感逻辑。要点:

1. 每设备维护完整 FCntUp/FCntDown(32 位),存数据库 2. 收到上行:取 16 位 FCnt,与本地完整值比对 3. 窗口判定: - 16 位值 ≈ 本地低 16 位 + 1 → 正常,更新 - 16 位值 > 本地低 16 位但差值 < 窗口 → 视为跳变,接受并同步 - 16 位值 ≤ 本地低 16 位且窗口外 → 重放,丢弃并告警 4. 窗口通常取 16384,超窗要求设备重新入网 ​

实现上两个坑:并发——同一设备的帧可能由多个网关同时上报,计数更新必须加锁或串行化,否则丢帧(已同步的计数被旧帧覆盖回退);持久化——NS 重启后计数丢失会拒绝所有存量设备的帧,计数要落库或允许按"设备上报的 16 位 + 假设"重建。

帧计数与 ADR 的相互作用

ADR 调整速率不会影响计数,但设备重启后计数从 NVM 恢复——若 NVM 丢失导致计数回到早期值,且 NS 的窗口判定通过(差值小于 16384),NS 会接受并把计数"拉高",此时旧帧重放窗口被意外打开。缓解:设备重启后主动重入网(计数清零重来),比靠窗口容忍更安全。这也是为什么很多运维规范要求"设备重启 = 重新入网"。

易错点补充

  • 下行计数不同步:设备侧要维护下行计数并拒绝倒退的下行帧,只防上行等于留了半扇门;
  • 窗口值写死不区分区域:窗口与协议版本、区域配置相关,做成参数而不是常量;
  • 重放告警泛滥:大批量重放告警会淹没真实故障,NS 要对同一 DevAddr 的重放做聚合与限频。

易错点清单

  • 设备侧不做下行计数校验:只防上行不防下行,等于把下行重放漏洞留给攻击者,双向都要校验;
  • 计数器持久化时机错误:应在"发送成功后"持久化而非发送前,避免"写入 NVM 时断电"造成计数未增或重复增;
  • 窗口同步逻辑过严或过松:窗口设 0 则正常跳变全拒收,设太大则重放窗口被拉长,16384 是社区常用折中;
  • 把帧计数当安全边界就够:帧计数只是防线之一,配合 OTAA 周期重入网才是完整策略。

要点回顾:32 位计数器按方向各维护一套,16 位线上传输、32 位本地维护;回绕与重启回退要靠重入网与 NVM 持久化兜底;重放攻击被"计数不递增即丢弃"机制挡住。安全账结清,下一章进入软件架构——这些账怎么在嵌入式代码里落地。

重放防护的纵深配合

帧计数只是重放防线的一层,成熟系统的纵深是:物理层(加密的调制信号本身难以伪造)→ MIC 层(篡改帧被完整性校验拦截)→ 帧计数层(重放旧帧被计数拦截)→ 业务层(关键指令带业务级流水号,重放的业务帧即使协议层通过也会在业务层被拒绝)。四层缺一不可:只靠帧计数,攻击者可以截获"计数最新的帧"反复重放;只靠业务流水号,攻击者仍然能制造大量无效流量消耗资源。

业务层的配合做法:关键指令(开关、解锁、参数下发)由应用侧生成单调递增的指令序号,设备侧校验"新指令序号必须大于已处理的最大序号",序号相同或更小的直接拒绝。这样即使攻击者拿到一条合法指令帧,也无法让它重复生效。

计数同步故障的运维处置

实际运维中"设备突然失联"排查到计数问题时的处置路径:第一步确认——在 NS 后台看该设备的最后帧计数与当前计数,若设备端计数远小于 NS 记录(重启回退),大概率是 NVM 未持久化;第二步恢复——让设备重新入网(OTAA 后计数清零重建),比手工改 NS 计数安全;第三步根治——更新固件,计数持久化到 NVM 并在重启后校验。不要手动修改 NS 侧计数:改错会打开重放窗口或误杀正常设备,宁可重入网。

易错点补充

  • 只做上行校验不做下行:下行重放(如重放"关阀"指令)与上行同等危险,双向都要防;
  • 计数跳变窗口开太大:为省事把窗口开到极大值,等于放弃了重放防护,窗口与重入网机制配合使用;
  • 重入网不清理旧会话:设备重入网后 NS 的旧会话记录要清理或标记,否则新旧会话并存造成计数混乱。

本节速查

小结与速查:32 位计数器按方向各一套,帧里只带 16 位;接收端按 (DevAddr, FCnt) 去重 + 窗口判定;回绕与重启回退靠重入网与 NVM 持久化;窗口取 16384 为社区常用值;双向都要校验;重放告警要聚合防淹没。

作者与出处
原作者:灏天文库
来源:平台策划编纂
整理人: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U