嵌入式安全概述
随着 IoT 设备爆炸式增长,嵌入式系统安全已成为关乎国家安全、企业命脉和个人隐私的核心议题。据统计,2025 年全球 IoT 设备数量突破 300 亿台,而其中超过 60% 的设备存在严重安全漏洞。从智能家居摄像头被黑客入侵,到工业控制系统遭受勒索软件攻击,安全事件频发警示我们:嵌入式安全不再是可选项,而是必选项。
本文深入探讨嵌入式安全开发的完整体系,涵盖安全启动、加密通信、安全存储、防攻击技术和安全开发生命周期,帮助开发者构建真正安全的嵌入式系统。
1.1 嵌入式安全威胁 landscape
| 威胁类型 | 典型攻击 | 影响 | 案例 |
|---|---|---|---|
| 固件篡改 | 恶意固件注入 | 设备被控制 | Mirai 僵尸网络 |
| 数据窃取 | 内存 dump、总线嗅探 | 隐私泄露 | 医疗数据泄露 |
| 侧信道攻击 | 功耗分析、时序分析 | 密钥泄露 | 智能卡破解 |
| 物理攻击 | 探针、FIB、激光注入 | 系统突破 | 游戏机越狱 |
| 供应链攻击 | 恶意组件、后门植入 | 系统性风险 | SolarWinds 事件 |
1.2 安全设计原则
嵌入式安全设计应遵循以下核心原则:
- 纵深防御(Defense in Depth):多层防护,单点失效不导致系统崩溃
- 最小权限(Least Privilege):每个组件只拥有完成任务所需的最小权限
- 失效安全(Fail Secure):系统故障时进入安全状态
- 安全默认配置(Secure by Default):出厂即安全,无需用户配置
- 安全更新(Secure Update):支持安全可靠的远程升级
安全启动(Secure Boot)
2.1 安全启动原理
安全启动的核心思想是信任链(Chain of Trust):从硬件固化的根信任开始,逐级验证每一级代码的完整性和真实性,确保只有可信代码能够执行。
┌─────────────────────────────────────────────────────────────┐
│ 安全启动信任链 │
├─────────────────────────────────────────────────────────────┤
│ ┌─────────────┐ │
│ │ 硬件根信任 │ ← 固化在 ROM 中,不可篡改 │
│ │ (Root of │ │
│ │ Trust) │ │
│ └──────┬──────┘ │
│ │ 验证签名 │
│ ▼ │
│ ┌─────────────┐ │
│ │ Bootloader │ ← 一级引导程序(验证二级引导) │
│ │ Stage 1 │ │
│ └──────┬──────┘ │
│ │ 验证签名 │
│ ▼ │
│ ┌─────────────┐ │
│ │ Bootloader │ ← 二级引导程序(验证应用固件) │
│ │ Stage 2 │ │
│ └──────┬──────┘ │
│ │ 验证签名 │
│ ▼ │
│ ┌─────────────┐ │
│ │ 应用固件 │ ← 最终执行代码 │
│ │ (Firmware) │ │
│ └─────────────┘ │
└─────────────────────────────────────────────────────────────┘
2.2 加密算法选择
安全启动依赖非对称加密算法进行签名验证:
| 算法 | 密钥长度 | 签名大小 | 验证速度 | 推荐场景 |
|---|---|---|---|---|
| RSA-2048 | 2048 位 | 256 字节 | 中等 | 通用场景 |
| RSA-3072 | 3072 位 | 384 字节 | 较慢 | 高安全场景 |
| ECDSA-P256 | 256 位 | 64 字节 | 快 | 资源受限 |
| ECDSA-P384 | 384 位 | 96 字节 | 中等 | 平衡场景 |
| Ed25519 | 256 位 | 64 字节 | 最快 | 推荐首选 |
2026 年推荐:优先选择 Ed25519 或 ECDSA-P256,在安全性和性能之间取得最佳平衡。
2.3 安全启动实现
// 安全启动验证流程(伪代码)
#include <mbedtls/rsa.h>
#include <mbedtls/sha256.h>
#include <mbedtls/pk.h>
// 公钥(固化在 Bootloader 中)
static const uint8_t public_key[] = {
// Ed25519 公钥(64 字节)
0x12, 0x34, 0x56, 0x78, ...
};
// 验证固件签名
int verify_firmware_signature(const uint8_t *firmware,
size_t firmware_size,
const uint8_t *signature,
size_t signature_size) {
mbedtls_pk_context pk;
mbedtls_pk_init(&pk);
// 1. 加载公钥
int ret = mbedtls_pk_parse_public_key(&pk, public_key, sizeof(public_key));
if (ret != 0) {
return -1; // 公钥解析失败
}
// 2. 计算固件哈希(SHA-256)
uint8_t hash[32];
ret = mbedtls_sha256_ret(firmware, firmware_size, hash, 0);
if (ret != 0) {
mbedtls_pk_free(&pk);
return -2; // 哈希计算失败
}
// 3. 验证签名
ret = mbedtls_pk_verify(&pk, MBEDTLS_MD_SHA256,
hash, sizeof(hash),
signature, signature_size);
mbedtls_pk_free(&pk);
if (ret == 0) {
return 0; // 验证成功
} else {
return -3; // 签名验证失败
}
}
// 启动流程
void secure_boot(void) {
firmware_header_t *header = (firmware_header_t*)FIRMWARE_ADDR;
// 1. 验证头部魔数
if (header->magic != FIRMWARE_MAGIC) {
halt_system("Invalid firmware magic");
}
// 2. 验证签名
if (verify_firmware_signature(header->payload,
header->payload_size,
header->signature,
header->sig_size) != 0) {
halt_system("Signature verification failed");
}
// 3. 验证通过,跳转到应用固件
jump_to_application(FIRMWARE_ADDR + header->header_size);
}
2.4 安全启动配置(STM32 示例)
// STM32H7 安全启动配置
void SecureBoot_Config(void) {
// 1. 启用 Flash 读保护(RDP Level 2)
FLASH_OBProgramInitTypeDef OBInit;
OBInit.OptionType = OPTIONBYTE_RDP;
OBInit.RDPLevel = OB_RDP_LEVEL_2; // 最高级别,调试接口永久禁用
HAL_FLASHEx_OBProgram(&OBInit);
// 2. 配置 PCROP(专有代码读保护)
OBInit.OptionType = OPTIONBYTE_PCROP;
OBInit.PCROPConfig = PCROP_ZONE_A;
OBInit.PCROPStartAddr = BOOTLOADER_END_ADDR;
OBInit.PCROPEndAddr = FIRMWARE_START_ADDR;
HAL_FLASHEx_OBProgram(&OBInit);
// 3. 启用写保护
OBInit.OptionType = OPTIONBYTE_WRP;
OBInit.WRPArea = OB_WRPAREA_BANK1;
OBInit.WRPStartOffset = 0;
OBInit.WRPEndOffset = BOOTLOADER_PAGES - 1;
HAL_FLASHEx_OBProgram(&OBInit);
// 4. 锁定选项字节
HAL_FLASH_OB_Launch();
}
加密通信
3.1 TLS/DTLS 协议选择
| 协议 | 传输层 | 特点 | 适用场景 |
|---|---|---|---|
| TLS 1.3 | TCP | 最安全、低延迟 | WiFi、以太网 |
| DTLS 1.3 | UDP | 支持丢包、低开销 | NB-IoT、LoRaWAN |
| mTLS | TCP/UDP | 双向认证 | 高安全场景 |
3.2 mTLS 双向认证实现
// mTLS 客户端配置(mbedTLS)
#include <mbedtls/ssl.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/entropy.h>
int setup_mtls_client(mbedtls_ssl_context *ssl,
const uint8_t *client_cert,
const uint8_t *client_key,
const uint8_t *ca_cert) {
mbedtls_ssl_config conf;
mbedtls_x509_crt cacert;
mbedtls_x509_crt clicert;
mbedtls_pk_context pkey;
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
// 初始化
mbedtls_ssl_config_init(&conf);
mbedtls_x509_crt_init(&cacert);
mbedtls_x509_crt_init(&clicert);
mbedtls_pk_init(&pkey);
mbedtls_entropy_init(&entropy);
mbedtls_ctr_drbg_init(&ctr_drbg);
// 1. 配置随机数生成器
const char *pers = "mtls_client";
mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
(const uint8_t *) pers, strlen(pers));
// 2. 加载 CA 证书
int ret = mbedtls_x509_crt_parse(&cacert, ca_cert, CA_CERT_LEN);
if (ret != 0) return -1;
// 3. 加载客户端证书
ret = mbedtls_x509_crt_parse(&clicert, client_cert, CLIENT_CERT_LEN);
if (ret != 0) return -2;
// 4. 加载客户端私钥
ret = mbedtls_pk_parse_key(&pkey, client_key, CLIENT_KEY_LEN, NULL, 0);
if (ret != 0) return -3;
// 5. 配置 SSL
mbedtls_ssl_config_defaults(&conf,
MBEDTLS_SSL_IS_CLIENT,
MBEDTLS_SSL_TRANSPORT_STREAM, // TLS
MBEDTLS_SSL_PRESET_DEFAULT);
// 6. 配置认证模式(强制双向认证)
mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_REQUIRED);
mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL);
// 7. 配置客户端证书和私钥
ret = mbedtls_ssl_conf_own_cert(&conf, &clicert, &pkey);
if (ret != 0) return -4;
// 8. 配置随机数生成器
mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
// 9. 应用配置
ret = mbedtls_ssl_setup(ssl, &conf);
if (ret != 0) return -5;
return 0;
}
3.3 轻量级加密协议
对于资源极度受限的设备,可考虑以下轻量级方案:
| 协议 | 密钥长度 | RAM 占用 | 适用场景 |
|---|---|---|---|
| ChaCha20-Poly1305 | 256 位 | ~2KB | ARM Cortex-M0/M3 |
| AES-128-CCM | 128 位 | ~3KB | 通用 IoT |
| Speck-Simon | 64-128 位 | ~1KB | 超低功耗 |
// ChaCha20-Poly1305 加密示例
#include <chacha20poly1305.h>
void encrypt_message(const uint8_t *plaintext, size_t len,
const uint8_t *key, const uint8_t *nonce,
uint8_t *ciphertext, uint8_t *tag) {
chacha20poly1305_state state;
// 初始化
chacha20poly1305_init(&state, key, 32);
// 加密
chacha20poly1305_encrypt(&state, nonce, plaintext, len,
ciphertext, tag);
// 清理状态
chacha20poly1305_cleanup(&state);
}
安全存储
4.1 安全存储架构
4.2 密钥管理
// 密钥派生(PBKDF2)
#include <mbedtls/pkcs5.h>
void derive_key(const uint8_t *password, size_t pwd_len,
const uint8_t *salt, size_t salt_len,
uint8_t *derived_key, size_t key_len) {
mbedtls_md_context_t md_ctx;
mbedtls_md_init(&md_ctx);
mbedtls_md_setup(&md_ctx, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), 1);
// PBKDF2-HMAC-SHA256,迭代 100000 次
mbedtls_pkcs5_pbkdf2_hmac(&md_ctx, password, pwd_len,
salt, salt_len, 100000,
key_len, derived_key);
mbedtls_md_free(&md_ctx);
}
// 安全存储密钥(加密后存储)
void store_encrypted_key(const uint8_t *key, size_t key_len,
const uint8_t *wrapping_key,
uint8_t *encrypted_key) {
mbedtls_aes_context aes;
mbedtls_aes_init(&aes);
mbedtls_aes_setkey_enc(&aes, wrapping_key, 256);
// AES-KW(密钥包裹)
mbedtls_aes_wrap_key(&aes, key_len / 8, encrypted_key, key);
mbedtls_aes_free(&aes);
}
4.3 安全元素(SE)集成
// 通过 I2C 访问安全元素(如 ATECC608A)
#include <i2c.h>
#include <atecc608a.h>
int se_generate_key(uint8_t slot_id, uint8_t *public_key) {
// 1. 生成 ECC P256 密钥对
uint8_t command[] = {0x47, 0x40, slot_id}; // GenKey 命令
uint8_t response[67];
i2c_write(ATECC_ADDR, command, sizeof(command));
i2c_read(ATECC_ADDR, response, sizeof(response));
// 2. 提取公钥
memcpy(public_key, response + 1, 64);
return 0;
}
int se_sign_data(uint8_t slot_id, const uint8_t *data, size_t len,
uint8_t *signature) {
// 1. 计算 SHA-256 哈希
uint8_t hash[32];
mbedtls_sha256_ret(data, len, hash, 0);
// 2. 使用 SE 签名
uint8_t command[36] = {0x41, 0x4A, slot_id};
memcpy(command + 3, hash, 32);
i2c_write(ATECC_ADDR, command, sizeof(command));
i2c_read(ATECC_ADDR, signature, 64); // ECDSA 签名(R + S)
return 0;
}
防攻击技术
5.1 侧信道攻击防护
(1)功耗分析攻击(DPA/SPA)
攻击原理:通过分析设备功耗变化推断密钥信息。
防护措施:
// 恒定时间实现(避免条件分支泄露信息)
uint8_t constant_time_compare(const uint8_t *a, const uint8_t *b, size_t len) {
uint8_t result = 0;
for (size_t i = 0; i < len; i++) {
result |= a[i] ^ b[i]; // 位运算,无条件分支
}
return (result == 0); // 0 = 相等,1 = 不等
}
// 掩码技术(随机化中间值)
void masked_aes_encrypt(const uint8_t *input, uint8_t *output,
const uint8_t *key, const uint8_t *mask) {
uint8_t masked_input[16];
// 输入掩码
for (int i = 0; i < 16; i++) {
masked_input[i] = input[i] ^ mask[i];
}
// 加密(使用掩码密钥)
aes_encrypt_masked(masked_input, output, key, mask);
// 输出解掩码
for (int i = 0; i < 16; i++) {
output[i] ^= mask[i];
}
}
(2)时序攻击防护
// 恒定时间字符串比较(防止时序攻击)
int secure_strcmp(const char *a, const char *b) {
volatile const char *pa = (volatile const char *)a;
volatile const char *pb = (volatile const char *)b;
volatile size_t i = 0;
volatile unsigned char result = 0;
while (pa[i] != '\0' || pb[i] != '\0') {
result |= pa[i] ^ pb[i];
i++;
}
return (result == 0) ? 0 : 1;
}
5.2 物理攻击防护
| 攻击方式 | 描述 | 防护措施 |
|---|---|---|
| 探针攻击 | 物理探针读取总线信号 | 总线加密、屏蔽层 |
| FIB 攻击 | 聚焦离子束修改电路 | 主动屏蔽层、传感器 |
| 激光注入 | 激光诱导故障 | 光传感器、金属层 |
| 温度攻击 | 极端温度诱导故障 | 温度传感器、自毁 |
// 主动屏蔽层检测
void check_active_shield(void) {
uint32_t shield_pattern = READ_SHIELD_REGISTER();
if (shield_pattern != EXPECTED_PATTERN) {
// 屏蔽层被破坏,清除敏感数据
secure_erase_keys();
system_halt();
}
}
// 温度监控
void check_temperature(void) {
int32_t temp = read_temperature_sensor();
if (temp < -20 || temp > 85) {
// 超出正常工作温度,可能遭受攻击
secure_erase_keys();
system_halt();
}
}
5.3 防重放攻击
// 时间戳 + 随机数防重放
typedef struct {
uint32_t timestamp;
uint8_t nonce[16];
uint8_t payload[];
} secure_message_t;
void send_secure_message(const uint8_t *payload, size_t len) {
secure_message_t *msg = pvPortMalloc(sizeof(secure_message_t) + len);
// 1. 设置时间戳(防止旧消息重放)
msg->timestamp = get_secure_timestamp();
// 2. 生成随机数(防止同时间戳重放)
generate_random_nonce(msg->nonce, sizeof(msg->nonce));
// 3. 复制 payload
memcpy(msg->payload, payload, len);
// 4. 计算 MAC
uint8_t mac[16];
calculate_hmac(msg, sizeof(secure_message_t) + len, mac);
// 5. 发送
transmit(msg, sizeof(secure_message_t) + len, mac, sizeof(mac));
vPortFree(msg);
}
int verify_message(const secure_message_t *msg, const uint8_t *mac) {
// 1. 验证时间戳(拒绝 5 分钟前的消息)
uint32_t current_time = get_secure_timestamp();
if (current_time - msg->timestamp > 300) {
return -1; // 消息过期
}
// 2. 检查随机数是否已使用(防重放)
if (is_nonce_used(msg->nonce)) {
return -2; // 重放攻击
}
// 3. 验证 MAC
uint8_t expected_mac[16];
calculate_hmac(msg, sizeof(secure_message_t) + msg->len, expected_mac);
if (constant_time_compare(mac, expected_mac, 16) != 0) {
return -3; // MAC 验证失败
}
// 4. 标记随机数为已使用
mark_nonce_as_used(msg->nonce);
return 0;
}
安全开发生命周期(SDL)
6.1 SDL 流程
┌─────────────────────────────────────────────────────────────┐
│ 安全开发生命周期(SDL) │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌───────────┐ │
│ │ 1. 培训 │ ← 所有开发人员接受安全培训 │
│ └─────┬─────┘ │
│ │ │
│ ┌─────▼─────┐ │
│ │ 2. 需求 │ ← 识别安全需求、合规要求 │
│ └─────┬─────┘ │
│ │ │
│ ┌─────▼─────┐ │
│ │ 3. 设计 │ ← 威胁建模、安全架构设计 │
│ └─────┬─────┘ │
│ │ │
│ ┌─────▼─────┐ │
│ │ 4. 实现 │ ← 安全编码规范、代码审查 │
│ └─────┬─────┘ │
│ │ │
│ ┌─────▼─────┐ │
│ │ 5. 验证 │ ← 渗透测试、模糊测试、静态分析 │
│ └─────┬─────┘ │
│ │ │
│ ┌─────▼─────┐ │
│ │ 6. 发布 │ ← 安全配置、漏洞响应计划 │
│ └─────┬─────┘ │
│ │ │
│ ┌─────▼─────┐ │
│ │ 7. 响应 │ ← 漏洞披露、补丁发布、OTA 更新 │
│ └───────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
6.2 威胁建模(STRIDE)
| 威胁类型 | 描述 | 示例 | 缓解措施 |
|---|---|---|---|
| Spoofing(欺骗) | 冒充合法实体 | 伪造设备 ID | 双向认证 |
| Tampering(篡改) | 修改数据/代码 | 固件篡改 | 数字签名 |
| Repudiation(抵赖) | 否认已执行操作 | 日志删除 | 审计日志 |
| Information Disclosure(信息泄露) | 未授权数据访问 | 密钥泄露 | 加密存储 |
| Denial of Service(拒绝服务) | 使服务不可用 | DDoS 攻击 | 限流、看门狗 |
| Elevation of Privilege(权限提升) | 获取未授权权限 | 缓冲区溢出 | 边界检查 |
6.3 安全编码规范
// 1. 始终检查返回值
int ret = mbedtls_ssl_read(ssl, buf, len);
if (ret < 0) {
if (ret != MBEDTLS_ERR_SSL_WANT_READ &&
ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
// 处理错误
handle_error(ret);
}
}
// 2. 边界检查(防止缓冲区溢出)
void safe_copy(char *dest, const char *src, size_t dest_size) {
if (dest == NULL || src == NULL || dest_size == 0) {
return;
}
size_t src_len = strlen(src);
size_t copy_len = (src_len < dest_size - 1) ? src_len : dest_size - 1;
memcpy(dest, src, copy_len);
dest[copy_len] = '\0';
}
// 3. 初始化所有变量
uint8_t key[32] = {0}; // 显式初始化为 0
mbedtls_aes_context aes;
mbedtls_aes_init(&aes); // 初始化结构体
// 4. 及时清理敏感数据
void process_key(const uint8_t *key, size_t len) {
uint8_t temp[32];
// 处理密钥
encrypt_data(key, temp);
// 清理临时数据
mbedtls_zeroize(temp, sizeof(temp));
}
// 5. 使用安全的随机数生成器
void generate_secure_random(uint8_t *buf, size_t len) {
// 不要使用 rand()!
// 使用加密安全的 RNG
mbedtls_ctr_drbg_random(&ctr_drbg, buf, len);
}
6.4 安全测试清单
| 测试类型 | 工具 | 频率 |
|---|---|---|
| 静态分析 | Coverity、SonarQube | 每次提交 |
| 动态分析 | Valgrind、AddressSanitizer | 每次构建 |
| 模糊测试 | AFL、libFuzzer | 每周 |
| 渗透测试 | 手动 + 自动化 | 每季度 |
| 代码审计 | 第三方安全公司 | 每年 |
安全认证与合规
7.1 常见安全认证
| 认证 | 适用领域 | 级别 | 成本 |
|---|---|---|---|
| Common Criteria | 通用 | EAL1-EAL7 | 高 |
| FIPS 140-2/3 | 美国政府 | Level 1-4 | 高 |
| PSA Certified | IoT | Level 1-3 | 中 |
| SESIP | IoT | Level 1-3 | 中 |
| IEC 62443 | 工业 | SL1-SL4 | 高 |
| ISO/SAE 21434 | 汽车 | - | 高 |
7.2 合规要求
| 法规 | 适用范围 | 要求 |
|---|---|---|
| GDPR | 欧盟 | 数据保护、隐私权 |
| CCPA | 美国加州 | 消费者隐私 |
| 网络安全法 | 中国 | 关键信息基础设施保护 |
| ETSI EN 303 645 | 欧盟 IoT | 基线安全要求 |
| NIST IR 8259 | 美国 IoT | 网络安全能力 |
总结
嵌入式安全开发的核心要点:
- 安全启动:建立信任链,确保只有可信代码执行
- 加密通信:使用 TLS/mTLS 保护数据传输
- 安全存储:加密敏感数据,使用安全元素
- 防攻击:侧信道防护、物理防护、防重放
- SDL:贯穿整个开发周期的安全实践
- 合规认证:满足行业标准和法规要求
安全不是一蹴而就的,而是一个持续的过程。从设计阶段就考虑安全,在开发过程中践行安全编码,在发布后进行持续监控和更新,才能构建真正安全的嵌入式系统。
本文基于 NIST、ENISA 安全指南、ARM PSA 认证框架和实际项目经验整理,结合 2026 年最新安全威胁态势编写。
参考资料
- NIST Cybersecurity for IoT Program - https://www.nist.gov/cybersecurity-iot
- ARM Platform Security Architecture (PSA) - https://developer.arm.com/Architecture/Security-Features/Platform-Security-Architecture
- Embedded Systems Security: Practical Strategies for Success (2025)
- IoT Security: Foundation to Cloud-to-Device (2026)
- mbedTLS Documentation - https://tls.mbed.org/
- Common Criteria Portal - https://www.commoncriteriaportal.org/