在嵌入式开发领域,提到“安全”二字,很多工程师可能会觉得那是网络安全专家的活儿,离自己写的底层代码有点远。但现实情况是,随着物联网设备深入到工控、车载、医疗等关键领域,嵌入式系统早已成为网络攻击的重要目标。
在探讨具体的技术方案之前,我们不妨先明确一个根本问题:嵌入式设备的安全保护,究竟在防什么?又该防谁?综合来看,主要的威胁可以归为三大类:
- 物理攻击 — 攻击者直接拿到设备实体,拆开外壳,将存储芯片焊接下来,用编程器直接读取固件内容。车载终端、工业控制机、医疗仪器等高价值设备是这类攻击的常见目标,目的是提取核心算法、加密密钥或用户敏感数据。
- 网络攻击 — 设备一旦联网,通信链路就成了攻击面。攻击者可以拦截设备与服务器之间的数据包,进行窃听、篡改,甚至伪装成合法的服务器向设备发送恶意指令。
- 固件攻击 — 攻击者通过各种手段(如利用OTA漏洞、物理接口等)将篡改后的恶意固件刷入设备。一旦成功,设备便完全受控于攻击者。
针对这三类威胁,一套完整的嵌入式安全防护体系通常需要构筑四道关键的防线,可以用一个简单的链条来概括:
Secure Boot → 存储加密 → 加密通信 → OTA 签名验证
第一道防线:Secure Boot (安全启动)
没有安全启动会怎样?
想象一下设备常规的启动流程:上电后,Bootloader 被加载并执行,随后它负责加载 Linux 内核,系统最终完成启动。在这个过程中,如果没有任何机制去校验这些被加载的代码是否合法、是否被篡改,那么攻击者只需将他修改过的固件刷入设备,设备便会“正常”启动,只不过运行的全是攻击者的代码。
信任链 (Chain of Trust) 是核心
Secure Boot 的核心思想在于构建一个信任链。它确保每一级代码在加载执行前,都必须先通过上一级的签名验证。
芯片内部 ROM (出厂固化,不可修改)
↓ 验证签名
Bootloader (厂商签名)
↓ 验证签名
Linux Kernel (厂商签名)
↓ 验证签名
Root Filesystem (厂商签名)
这个过程始于芯片内部不可更改的 ROM,其中固化了最初的根公钥。ROM 代码会验证 Bootloader 的数字签名,只有验证通过才会执行它。Bootloader 随后用同样的方式验证内核,内核再验证根文件系统,如此一环扣一环。签名用的私钥由设备厂商严格保管,对应的公钥则被烧录到芯片的 eFuse 等一次性可编程存储器中。任何一环的代码被篡改,都会导致签名验证失败,启动过程中止。
实际落地注意事项
- 私钥保管 — 这是整个信任链的基石。一旦签名私钥泄漏,整个安全启动机制形同虚设。务必使用 HSM(硬件安全模块)等专业方案进行私钥的生成、存储和使用。
- 实现回滚保护 — 防止攻击者将设备固件降级到存在已知漏洞的旧版本。通常需要维护一个单调递增的版本计数器并与固件绑定验证。
- 开发阶段谨慎操作 eFuse — eFuse 一旦烧录便不可逆转。在产品开发验证阶段,建议先采用软件可配置的方式模拟验证流程,待方案完全稳定后再进行最终的 eFuse 烧录。
第二道防线:存储加密
物理攻击的便捷性超出想象
对于一个有经验的攻击者,拿到一块电路板后,可能只需要十分钟就能将 Flash 或 EMMC 存储芯片焊接下来,通过通用编程器读出全部二进制内容。届时,你的固件、配置文件、加密密钥乃至用户数据都将一览无余。存储加密的目标非常明确:即使存储芯片被物理拆走,读出来的也只是一堆无法理解的密文。
如何实现存储加密?
主流方案是依靠芯片本身提供的硬件加解密引擎和安全存储区域。芯片在安全区域内生成一个唯一的随机密钥,当数据写入外部存储介质时,由硬件自动加密;读取时,再自动解密。整个过程,密钥永远不会离开芯片的安全边界。攻击者即便拿到了存储芯片,因为没有对应的那颗芯片(及其内部的密钥),也无法解密出有效信息。
可能遇到的坑
- 调试复杂度增加 — 开启存储加密后,原本通过 JTAG 读取内存、或者直接从存储芯片 DUMP 数据进行调试分析的方法可能会失效。建议在功能开发验证阶段先不开启,待主要功能稳定后,在量产前再作为最后一步启用。
- “密钥不可导出”是特性,不是 Bug — 这带来了一个重要的生产与维护考量:你必须妥善保管好最终的、可加密写入的原始固件镜像。一旦设备需要维修或返厂,没有原始密钥就无法恢复用户数据或直接更换空白的存储芯片,整个生产、烧录、售后流程都需要为此设计。
第三道防线:加密通信
明文通信的风险
如果设备与服务器之间使用 HTTP 等明文协议通信,那么在同一局域网内的任何攻击者,使用 Wireshark 之类的抓包工具就能轻松窥探所有交互内容。
比窃听更危险的是中间人攻击 — 攻击者伪装成服务器,与设备建立连接,并向设备发送伪造的控制指令。对于工控设备(如PLC)、医疗设备(如输液泵)等,一旦执行了恶意指令,后果不堪设想。
TLS 协议的双重保障
TLS(传输层安全协议)为通信提供了两大核心保障:
- 加密 — 对通信内容进行高强度加密,确保第三方无法窃听和理解。
- 身份验证 — 设备可以验证服务器证书的真实性,确认自己连接的是“正牌”服务器,而非中间人伪装的。
在嵌入式领域,常用的 TLS 库包括 Mbed TLS(轻量级,适合资源受限的 MCU 环境)和 OpenSSL(功能全面,常用于性能更强的 Linux 系统)。
更高安全要求:双向认证 (mTLS)
标准的 TLS 通常只要求客户端(设备)验证服务器。在工业控制、智能汽车、高端医疗设备等对安全性要求极高的场景中,往往会启用双向 TLS 认证。这意味着服务器也必须验证客户端(设备)的证书,只有持有合法证书的设备才能接入网络,进一步杜绝了非法设备仿冒接入的风险。
一个最常见且致命的错误
在实际开发中,为了方便调试,开发者可能会暂时关闭证书验证功能。可怕的是,有时这个“临时”设置会被遗忘,直接进入了量产固件。
// 开发时图方便关掉了验证,量产时忘了改回来
// 这行代码会让整个TLS连接毫无安全性可言
mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_NONE);
上面这行代码,足以让整套精心设计的加密通信体系彻底失效。遗憾的是,这类错误在现实中并非个例。
第四道防线:OTA 签名验证
OTA 是最危险的入口
远程固件升级是现代嵌入式产品的标配功能,极大便利了功能迭代和漏洞修复。但这也使其成为攻击者眼中最高危的攻击入口——一旦攻击者能通过OTA渠道向设备推送一个恶意固件,就等于将整个设备的控制权拱手相让。
安全 OTA 的标准流程
一个具备完整安全性的 OTA 流程应该如下所示:
开发者使用私钥对固件镜像进行签名
↓
固件包(含镜像和签名)上传至安全的OTA服务器
↓
设备通过加密通道(如上述TLS)下载固件包
↓
设备使用预先烧录在安全存储中的公钥验证固件签名
↓
验证通过 → 将固件写入升级分区 → 重启生效
验证失败 → 丢弃固件包,保持现有系统不变
只要签名私钥得到妥善保管,攻击者无法伪造出能通过验证的签名,此路便被彻底堵死。
A/B 分区:为升级加上“保险丝”
OTA 升级过程中,最令人担忧的意外就是断电,可能导致设备“变砖”。A/B 分区(或称无缝升级)方案是应对此问题的有效策略,它为升级过程提供了一个可靠的“回滚”备份:
当前运行分区:A
↓
下载新固件 → 写入空闲的 B 分区
↓
验证签名通过 → 重启并从 B 分区启动
↓
启动成功 → B 分区成为新的活动分区
启动失败 → 自动回滚至 A 分区启动
在这种设计下,设备始终保留一个已知良好的可启动备份,即使升级失败或新固件有缺陷,也能自动恢复,保障了系统的可用性。
四道防线,环环相扣
我们来总结一下威胁与防线的对应关系:
威胁类型 对应防线
──────────────────────────────────
刷入恶意固件 → Secure Boot (安全启动)
拆机读取数据 → 存储加密
窃听篡改通信 → TLS 加密通信
伪造 OTA 包 → OTA 签名验证
必须强调的是,这四道防线并非彼此孤立,而是环环相扣、互为支撑的:
- Secure Boot 确保了设备启动链的纯净,保护了 OTA 客户端本身不被恶意代码替换。
- 存储加密 保护了设备内部用于 TLS 或 OTA 验证的私钥或证书不被物理提取。
- TLS 加密通信 为 OTA 固件包的下载过程提供了安全的传输通道,防止固件在传输中被劫持或篡改。
任何一环的缺失或脆弱,都可能导致整个安全链条从最薄弱处被攻破。
嵌入式工程师的安全责任
安全防护这件事,在嵌入式领域有着独特的权重。上层应用或许有框架提供保护,云端可能有专业的安全团队运维,但嵌入式这一层——从 Bootloader 的启动流程、到内核的配置、再到应用程序的网络通信和 OTA 逻辑——代码的实现者正是嵌入式工程师。
安全不仅仅是复杂的加密算法和密码学理论,它更是贯穿于开发习惯、架构设计、密钥管理和生产流程中的一种系统性思维。养成时刻关注安全的习惯,其重要性远胜于学习任何单一的工具。当然,除了上述软件方案,使用独立的安全芯片(SE/TEE)来托管密钥和运算,也是更高安全等级场景下的重要硬件方案。
你当前负责的嵌入式项目中,这四道安全防线落实了几道?在实际开发中又遇到了哪些挑战?欢迎在技术社区分享你的实践经验。
