物联网设备安全加固:固件加密与安全启动实战

物联网设备安全加固:固件加密与安全启动实战

你的 IoT 设备裸奔了吗?

很多开发者把 ESP32 程序烧进去就跑,完全没想过一个问题:别人把你的板子拆下来,用编程器读一下 Flash,整个固件就到手了。里面可能有 WiFi 密码、API 密钥、私有协议逻辑,甚至商业算法。今天咱们就来聊聊怎么给 IoT 设备穿上”防弹衣”——安全启动(Secure Boot)+ Flash 加密

为什么要做固件安全?

先说个真实场景:你做了一个智能门锁,ESP32 负责蓝牙通信和电机控制。某天竞争对手买了你的产品,拆开外壳,用 SPI 编程器把 Flash 芯片里的数据全读出来。反编译一看,蓝牙配对密钥、开锁协议、甚至云端 API 的 secret key 全部明文躺着。接下来他们就能克隆你的产品,或者直接破解开锁流程。

这就是不做固件安全的后果。安全启动 + Flash 加密就是为了解决这两个核心问题:

  1. $1

  2. $1

ESP32(v3.0 及以上芯片版本)支持的是 Secure Boot v2,基于 RSA-PSS 签名方案,比 v1 更安全也更灵活。下面咱们一步步实操。

硬件清单

组件型号/规格说明
开发板ESP32-WROOM-32 / ESP32-S3芯片版本需 v3.0 以上
USB 线Micro-USB / USB-C用于烧录和串口调试
电脑Windows / macOS / Linux安装 ESP-IDF 开发环境
ESP-IDFv5.0+乐鑫官方开发框架

**

注意**:老版本的 ESP32(芯片 revision < v3.0)只支持 Secure Boot v1,本文以 v2 为准。你可以在终端运行 esptool chip_id 查看芯片版本信息。

核心概念:安全启动是怎么工作的?

安全启动的核心思路是信任链(Chain of Trust)

ROM 代码(不可修改) → 验证二级 bootloader 签名 → 验证 App 固件签名 → 运行应用
  1. $1

  2. $1

  3. $1

整个过程的关键在于:私钥永远不存储在设备上,只存在你的开发电脑或更安全的离线环境中。设备上只有公钥摘要(存在 eFuse 里),攻击者即使拿到板子也无法伪造签名。

第一步:生成签名密钥

在项目目录下执行:

idf.py secure-generate-signing-key signing_key.pem

这会生成一个 RSA-3072 的 PEM 格式密钥文件 signing_key.pem这个文件就是你的命根子,务必妥善保管,建议:

  • 备份到离线 U 盘

  • 不要上传到 Git

  • 生产环境下用 HSM(硬件安全模块)或离线电脑生成

如果你担心 idf.py 生成的随机数不够安全,可以用 OpenSSL 手动生成:

openssl genrsa -out signing_key.pem 3072

第二步:配置 menuconfig

运行 idf.py menuconfig,进入以下配置项:

启用安全启动 v2

Security features →
  [✓] Enable hardware Secure Boot in bootloader
  Secure Boot Version → Secure Boot V2 (RSA-PSS)

设置芯片最低版本

Component config → ESP32-specific →
  Minimum Supported ESP32 Revision → v3.0

指定签名密钥路径

Security features →
  (/path/to/signing_key.pem) Signing key file path

(可选)禁用 UART 下载模式

Security features →
  [ ] Allow UART ROM download mode

**

警告**:禁用 UART 下载模式后,你将无法再通过串口重新烧录固件。如果后续需要 OTA 升级,确保 OTA 功能已正确配置。开发阶段建议保持开启,量产前再关闭。

启用 Flash 加密(可选但推荐)

Security features →
  [✓] Enable flash encryption on boot (RELEASE_ON_BOOT)
  Flash encryption mode → DEVELOPMENT (开发阶段) / RELEASE (生产阶段)
  • DEVELOPMENT 模式:每次烧录时自动重新加密,方便调试。

  • RELEASE 模式:只加密一次,之后 Flash 内容永久加密,无法再明文读取或修改。

第三步:构建并烧录

构建 bootloader

idf.py bootloader

构建完成后,终端会提示你烧录 bootloader 的命令,类似:

esptool.py --port /dev/ttyUSB0 write_flash 0x0 build/bootloader/bootloader.bin

手动执行这条命令,将签名后的 bootloader 烧录到地址 0x0

构建并烧录 App

idf.py flash

**

注意**:启用安全启动后,idf.py flash 不会烧录 bootloader,只会烧录分区表和 App 固件。这是为了防止意外覆盖已签名的 bootloader。

首次启动

复位 ESP32,观察串口输出。你应该看到类似以下内容:

I (xxx) boot: Secure boot V2 enabled
I (xxx) boot: Validating app image...
I (xxx) boot: App image verified successfully

如果看到 Secure boot verification failed 或启动卡住,说明签名验证失败。常见原因:

  • 密钥不匹配(用了不同的密钥签名)

  • eFuse 未正确写入公钥摘要

  • Flash 加密配置冲突

第四步:验证安全效果

测试 1:尝试烧录未签名固件

用另一个未启用安全启动的项目构建固件,尝试烧录:

# 在未启用安全启动的项目中
idf.py flash

复位后,设备会拒绝启动,串口输出类似:

E (xxx) boot: Secure boot verification failed! Halting...

测试 2:读取 Flash 内容

esptool 读取 Flash:

esptool.py --port /dev/ttyUSB0 read_flash 0x0 0x400000 flash_dump.bin

如果启用了 Flash 加密(RELEASE 模式),flash_dump.bin 里的内容是加密的,直接用 strings 或反编译工具看不到任何有意义的信息。

常见问题排查

Q1:启用安全启动后无法再烧录怎么办?

A:如果你禁用了 UART 下载模式且没有配置 OTA,那就真的”砖”了。解决方案:

  • 开发阶段不要禁用 UART 下载模式

  • 配置 OTA 功能,通过无线方式更新固件

  • 使用 JTAG 调试接口烧录(需要额外硬件)

Q2:Flash 加密后调试变得困难?

A:开发阶段使用 DEVELOPMENT 模式,每次 idf.py flash 会自动重新加密,不影响调试。切换到 RELEASE 模式后再做最终测试。

Q3:OTA 升级时如何处理签名?

A:OTA 固件必须用同一个私钥签名。在 OTA 服务器端,用以下命令签名新固件:

idf.py secure-sign-app build/app.bin signed_app.bin

然后推送 signed_app.bin 到设备。ESP32 的 OTA 机制会自动验证签名,失败则回滚到旧版本。

Q4:eFuse 写错能恢复吗?

A不能。eFuse 是一次性可编程存储器(OTP),一旦写入就无法撤销。这也是为什么建议在开发阶段充分测试,确认配置无误后再烧录 eFuse。

Q5:性能影响大吗?

A:安全启动的签名验证只在启动时执行一次,增加约 100-200ms 启动时间,对大多数 IoT 应用可以忽略。Flash 加密/解密由硬件加速,运行时几乎没有性能损耗。

生产环境最佳实践

  1. $1

  2. $1

  3. $1

  4. $1

  5. $1

小结

给 IoT 设备做安全加固,核心就两件事:

  • 安全启动:确保只有你签名的固件能跑

  • Flash 加密:确保固件内容不会被物理读取

ESP32 的 Secure Boot v2 + Flash 加密方案已经非常成熟,配置起来也不复杂。关键是养成习惯——从第一个项目开始就把安全考虑进去,而不是等到产品上市后被破解才补救。

如果你的设备涉及用户隐私、支付信息或商业机密,这套方案几乎是必选项。毕竟,没人想成为下一个”智能门锁被批量克隆”的新闻主角吧?

参考资料:ESP-IDF 安全启动 v2 官方文档