嵌入式系统安全概述¶
概述¶
随着物联网和智能设备的普及,嵌入式系统安全已成为产品开发中不可忽视的关键要素。从智能家居到工业控制,从医疗设备到汽车电子,安全漏洞可能导致严重的后果。完成本文学习后,你将能够:
- 理解嵌入式系统面临的主要安全威胁
- 掌握安全需求分析的基本方法
- 了解安全设计的核心原则
- 熟悉主要的安全标准和规范
- 掌握基本的安全防护措施
背景知识¶
为什么嵌入式安全如此重要?¶
嵌入式系统安全的重要性体现在多个方面:
1. 物理接触风险 - 设备通常部署在无人看管的环境 - 攻击者可能直接接触硬件 - 调试接口可能被恶意利用
2. 长生命周期 - 设备可能运行数年甚至数十年 - 难以及时更新和修补漏洞 - 需要考虑长期的安全威胁
3. 资源受限 - 计算能力和存储空间有限 - 难以实现复杂的安全机制 - 需要在安全性和性能间平衡
4. 安全影响广泛 - 智能家居:隐私泄露 - 工业控制:生产中断 - 医疗设备:生命安全 - 汽车电子:行车安全
前置知识要求¶
本文假设你已经掌握: - 嵌入式系统基础知识 - 基本的编程能力 - 计算机网络基础概念
核心内容¶
1. 嵌入式系统安全威胁¶
1.1 物理攻击¶
物理攻击是指攻击者通过直接接触设备进行的攻击。
常见物理攻击类型:
- 调试接口攻击
- JTAG/SWD接口未关闭
- UART调试端口暴露
-
通过调试接口读取固件
-
侧信道攻击
- 功耗分析(Power Analysis)
- 电磁辐射分析(EM Analysis)
- 时序分析(Timing Analysis)
-
通过物理特征推断密钥
-
硬件篡改
- 芯片解封装
- 探针攻击
- 故障注入(Fault Injection)
- 修改硬件电路
防护措施: - 禁用或保护调试接口 - 使用安全芯片存储敏感数据 - 实施物理防篡改检测 - 采用屏蔽和加固技术
1.2 软件攻击¶
软件攻击通过利用代码漏洞来获取系统控制权。
常见软件攻击类型:
- 缓冲区溢出
- 栈溢出攻击
- 堆溢出攻击
-
覆盖返回地址或函数指针
-
代码注入
- 命令注入
- SQL注入(如果使用数据库)
-
脚本注入
-
恶意固件
- 固件替换
- 固件篡改
- 后门植入
防护措施: - 输入验证和边界检查 - 使用安全的编程实践 - 固件签名验证 - 代码审计和静态分析
1.3 网络攻击¶
随着物联网的发展,网络攻击成为主要威胁。
常见网络攻击类型:
- 中间人攻击(MITM)
- 拦截通信数据
- 篡改传输内容
-
窃取敏感信息
-
拒绝服务攻击(DoS)
- 资源耗尽
- 系统崩溃
-
服务不可用
-
重放攻击
- 捕获合法数据包
- 重新发送以欺骗系统
-
绕过认证机制
-
固件劫持
- 拦截固件更新
- 注入恶意固件
- 远程控制设备
防护措施: - 使用加密通信(TLS/DTLS) - 实施身份认证和授权 - 防重放机制(时间戳、随机数) - 安全的固件更新机制
1.4 供应链攻击¶
供应链攻击在开发和生产过程中植入恶意代码。
攻击途径: - 第三方库和组件 - 开发工具链 - 生产环境 - 物流运输
防护措施: - 供应商安全评估 - 代码和组件审计 - 安全的开发环境 - 生产过程监控
2. 安全需求分析¶
2.1 CIA三要素¶
信息安全的核心目标可以用CIA三要素概括:
1. 机密性(Confidentiality) - 确保信息不被未授权访问 - 数据加密存储和传输 - 访问控制机制
2. 完整性(Integrity) - 确保数据未被篡改 - 数据校验和签名 - 防止未授权修改
3. 可用性(Availability) - 确保系统正常运行 - 防止拒绝服务攻击 - 故障恢复机制
2.2 威胁建模¶
威胁建模是识别和评估安全风险的系统方法。
STRIDE威胁模型:
| 威胁类型 | 说明 | 示例 |
|---|---|---|
| **S**poofing(欺骗) | 伪装成其他实体 | 伪造设备ID |
| **T**ampering(篡改) | 未授权修改数据 | 修改配置参数 |
| **R**epudiation(抵赖) | 否认操作行为 | 无法追踪操作记录 |
| **I**nformation Disclosure(信息泄露) | 暴露敏感信息 | 密钥泄露 |
| **D**enial of Service(拒绝服务) | 使系统不可用 | 资源耗尽 |
| **E**levation of Privilege(权限提升) | 获取更高权限 | 普通用户获取管理员权限 |
威胁建模步骤:
- 识别资产
- 敏感数据(密钥、用户信息)
- 关键功能(认证、控制)
-
系统资源(CPU、内存)
-
识别威胁
- 使用STRIDE模型
- 分析攻击面
-
考虑攻击者能力
-
评估风险
- 威胁发生概率
- 潜在影响程度
-
风险等级划分
-
制定对策
- 消除威胁
- 降低风险
- 转移风险
- 接受风险
2.3 安全等级划分¶
根据系统的安全需求,可以划分不同的安全等级。
通用安全等级:
- Level 0:无安全要求
- 公开信息
- 无敏感数据
-
无安全威胁
-
Level 1:基本安全
- 基本访问控制
- 简单加密
-
日志记录
-
Level 2:中等安全
- 强认证机制
- 数据加密
- 安全启动
-
固件签名
-
Level 3:高安全
- 多因素认证
- 硬件安全模块
- 安全隔离
-
实时监控
-
Level 4:极高安全
- 军事级加密
- 物理防护
- 形式化验证
- 严格审计
3. 安全设计原则¶
3.1 纵深防御(Defense in Depth)¶
不依赖单一安全措施,而是建立多层防护。
多层防护示例:
┌─────────────────────────────────────┐
│ 物理层:防篡改、屏蔽、加固 │
├─────────────────────────────────────┤
│ 硬件层:安全芯片、加密引擎 │
├─────────────────────────────────────┤
│ 启动层:安全启动、固件验证 │
├─────────────────────────────────────┤
│ 系统层:访问控制、权限管理 │
├─────────────────────────────────────┤
│ 应用层:输入验证、安全编码 │
├─────────────────────────────────────┤
│ 网络层:加密通信、防火墙 │
└─────────────────────────────────────┘
实施要点: - 每层独立防护 - 层与层之间相互支持 - 单层失效不影响整体安全 - 增加攻击难度和成本
3.2 最小权限原则(Principle of Least Privilege)¶
每个组件只拥有完成任务所需的最小权限。
应用示例:
- 进程权限
- 普通任务以低权限运行
- 只在必要时提升权限
-
及时降低权限
-
文件访问
- 只读权限用于配置文件
- 写权限仅限必要目录
-
执行权限严格控制
-
网络访问
- 限制可访问的端口
- 白名单机制
- 最小化攻击面
3.3 默认安全(Secure by Default)¶
系统默认配置应该是安全的。
设计要点:
- 默认关闭不必要的功能
- 调试接口默认禁用
- 不必要的服务不启动
-
测试功能不进入生产版本
-
强制安全配置
- 强制修改默认密码
- 必须启用加密
-
自动安全更新
-
安全的默认值
- 最严格的访问控制
- 最强的加密算法
- 最短的超时时间
3.4 故障安全(Fail-Safe)¶
系统在出现故障时应该保持安全状态。
设计策略:
- 安全失效模式
- 认证失败时拒绝访问
- 加密失败时停止通信
-
验证失败时拒绝执行
-
异常处理
- 捕获所有异常
- 记录异常信息
-
安全地恢复或关闭
-
看门狗机制
- 检测系统异常
- 自动重启恢复
- 防止系统挂死
3.5 开放设计(Open Design)¶
安全性不应依赖于算法的保密,而应依赖于密钥的保密。
Kerckhoffs原则: - 使用公开的、经过验证的加密算法 - 不要自己发明加密算法 - 安全性依赖于密钥管理 - 算法公开有利于发现漏洞
实践建议: - 使用标准加密算法(AES、RSA) - 使用成熟的安全协议(TLS) - 参与安全社区审查 - 定期安全审计
3.6 完全中介(Complete Mediation)¶
每次访问都必须经过权限检查。
实施要点:
- 不信任缓存的权限
- 每次访问都验证
- 不依赖之前的检查结果
-
防止权限变更后的漏洞
-
集中的访问控制
- 统一的权限检查点
- 一致的安全策略
-
便于审计和维护
-
无法绕过的检查
- 所有访问路径都检查
- 防止直接访问
- 强制执行安全策略
4. 安全标准与规范¶
4.1 通用安全标准¶
ISO/IEC 27001 - 信息安全管理体系 - 适用于所有类型的组织 - 关注管理和流程
Common Criteria (CC) - 信息技术安全评估标准 - 评估保证级别(EAL1-EAL7) - 国际通用认证
NIST Cybersecurity Framework - 美国国家标准与技术研究院 - 网络安全框架 - 识别、保护、检测、响应、恢复
4.2 行业特定标准¶
汽车行业 - ISO 26262:功能安全 - ISO/SAE 21434:网络安全 - AUTOSAR:汽车软件架构
工业控制 - IEC 62443:工业自动化和控制系统安全 - NERC CIP:关键基础设施保护
医疗设备 - IEC 62304:医疗设备软件生命周期 - FDA Guidance:医疗设备网络安全指南
物联网 - ETSI EN 303 645:消费类物联网安全 - IoT Security Foundation:物联网安全最佳实践
4.3 编码安全标准¶
MISRA C - 嵌入式C编程规范 - 避免未定义行为 - 提高代码可靠性和安全性
CERT C Coding Standard - 安全编码规则 - 常见漏洞防范 - 由CERT/CC维护
CWE (Common Weakness Enumeration) - 软件弱点分类 - 常见安全漏洞 - 漏洞数据库
5. 基本防护措施¶
5.1 安全启动¶
安全启动确保只有经过验证的固件才能运行。
安全启动流程:
┌──────────────┐
│ ROM Bootloader │ ← 硬件信任根
│ (不可修改) │
└────────┬─────────┘
│ 验证签名
↓
┌──────────────┐
│ Bootloader │
│ (可更新) │
└────────┬─────────┘
│ 验证签名
↓
┌──────────────┐
│ Application │
│ Firmware │
└──────────────┘
实施要点: - 使用数字签名验证固件 - 建立信任链 - 防止回滚攻击 - 失败时拒绝启动
5.2 固件保护¶
代码保护: - 读保护(RDP) - 写保护 - 调试接口禁用 - 防止固件提取
固件加密: - 存储加密 - 传输加密 - 密钥管理 - 防止逆向工程
5.3 安全通信¶
传输层安全: - TLS/DTLS协议 - 证书验证 - 加密通信 - 防止中间人攻击
应用层安全: - 消息认证码(MAC) - 数字签名 - 时间戳和随机数 - 防重放攻击
5.4 密钥管理¶
密钥生成: - 使用硬件随机数生成器 - 足够的密钥长度 - 定期更新密钥
密钥存储: - 使用安全芯片(SE/TEE) - 加密存储 - 访问控制 - 防止提取
密钥分发: - 安全的密钥交换协议 - 证书管理 - 密钥撤销机制
5.5 访问控制¶
身份认证: - 密码认证 - 证书认证 - 生物特征认证 - 多因素认证
授权管理: - 基于角色的访问控制(RBAC) - 访问控制列表(ACL) - 最小权限原则 - 权限审计
5.6 安全日志¶
日志记录: - 记录安全事件 - 登录尝试 - 权限变更 - 异常行为
日志保护: - 防篡改 - 加密存储 - 定期备份 - 安全传输
日志分析: - 实时监控 - 异常检测 - 安全审计 - 事件响应
实践示例¶
示例1:简单的安全启动验证¶
以下是一个简化的安全启动验证示例:
#include <stdint.h>
#include <string.h>
// 简化的RSA签名验证(实际应使用加密库)
typedef struct {
uint8_t signature[256];
uint32_t firmware_size;
uint32_t firmware_crc;
} firmware_header_t;
// 验证固件签名
int verify_firmware_signature(const firmware_header_t *header,
const uint8_t *firmware,
const uint8_t *public_key) {
// 实际实现应使用RSA或ECDSA验证
// 这里仅作示意
// 1. 计算固件哈希
uint32_t calculated_hash = calculate_hash(firmware, header->firmware_size);
// 2. 使用公钥验证签名
int valid = rsa_verify(public_key, header->signature,
(uint8_t*)&calculated_hash, sizeof(calculated_hash));
return valid;
}
// 安全启动流程
void secure_boot(void) {
firmware_header_t *header = (firmware_header_t*)FIRMWARE_HEADER_ADDR;
uint8_t *firmware = (uint8_t*)FIRMWARE_START_ADDR;
uint8_t *public_key = (uint8_t*)PUBLIC_KEY_ADDR;
// 验证固件签名
if (!verify_firmware_signature(header, firmware, public_key)) {
// 签名验证失败,拒绝启动
error_handler("Firmware signature verification failed");
while(1); // 停止启动
}
// 验证固件版本(防回滚)
if (header->firmware_version < get_minimum_version()) {
error_handler("Firmware version too old");
while(1);
}
// 签名验证成功,跳转到应用程序
jump_to_application(FIRMWARE_START_ADDR);
}
代码说明: - 验证固件数字签名 - 检查固件版本防止回滚 - 验证失败时拒绝启动 - 实际应用需使用成熟的加密库
示例2:安全的数据存储¶
#include <stdint.h>
#include <string.h>
// 加密存储结构
typedef struct {
uint8_t iv[16]; // 初始化向量
uint8_t encrypted_data[256];
uint8_t mac[32]; // 消息认证码
} secure_storage_t;
// 安全存储数据
int secure_store_data(const uint8_t *data, uint32_t len,
const uint8_t *key) {
secure_storage_t storage;
// 1. 生成随机IV
generate_random(storage.iv, sizeof(storage.iv));
// 2. 使用AES-CBC加密数据
aes_cbc_encrypt(data, len, key, storage.iv,
storage.encrypted_data);
// 3. 计算MAC保证完整性
hmac_sha256(storage.encrypted_data, len, key, storage.mac);
// 4. 写入存储
return write_to_flash(&storage, sizeof(storage));
}
// 安全读取数据
int secure_read_data(uint8_t *data, uint32_t len,
const uint8_t *key) {
secure_storage_t storage;
// 1. 从存储读取
if (read_from_flash(&storage, sizeof(storage)) != 0) {
return -1;
}
// 2. 验证MAC
uint8_t calculated_mac[32];
hmac_sha256(storage.encrypted_data, len, key, calculated_mac);
if (memcmp(storage.mac, calculated_mac, sizeof(storage.mac)) != 0) {
// MAC验证失败,数据可能被篡改
return -1;
}
// 3. 解密数据
aes_cbc_decrypt(storage.encrypted_data, len, key,
storage.iv, data);
return 0;
}
代码说明: - 使用AES加密保护机密性 - 使用HMAC保护完整性 - 使用随机IV防止模式攻击 - 先验证MAC再解密
示例3:输入验证¶
#include <stdint.h>
#include <stdbool.h>
#include <ctype.h>
// 验证用户名(只允许字母数字和下划线)
bool validate_username(const char *username, uint32_t max_len) {
if (username == NULL) {
return false;
}
uint32_t len = 0;
while (username[len] != '\0') {
// 检查长度
if (len >= max_len) {
return false;
}
// 检查字符合法性
char c = username[len];
if (!isalnum(c) && c != '_') {
return false;
}
len++;
}
// 检查最小长度
if (len < 3) {
return false;
}
return true;
}
// 安全的字符串复制
void safe_string_copy(char *dest, const char *src,
uint32_t dest_size) {
if (dest == NULL || src == NULL || dest_size == 0) {
return;
}
uint32_t i;
for (i = 0; i < dest_size - 1 && src[i] != '\0'; i++) {
dest[i] = src[i];
}
dest[i] = '\0'; // 确保字符串终止
}
// 验证数值范围
bool validate_range(int32_t value, int32_t min, int32_t max) {
return (value >= min && value <= max);
}
// 使用示例
void process_user_input(const char *username, int32_t age) {
// 验证用户名
if (!validate_username(username, 32)) {
log_error("Invalid username");
return;
}
// 验证年龄范围
if (!validate_range(age, 0, 150)) {
log_error("Invalid age");
return;
}
// 安全复制
char safe_username[32];
safe_string_copy(safe_username, username, sizeof(safe_username));
// 处理验证通过的数据
process_validated_data(safe_username, age);
}
代码说明: - 严格的输入验证 - 防止缓冲区溢出 - 范围检查 - 字符合法性检查
深入理解¶
安全与性能的平衡¶
嵌入式系统资源有限,需要在安全性和性能之间找到平衡。
权衡考虑:
- 加密算法选择
- 对称加密(AES):快速,适合大量数据
- 非对称加密(RSA/ECC):慢,适合密钥交换和签名
-
哈希算法(SHA-256):中等速度,用于完整性验证
-
硬件加速
- 使用硬件加密引擎
- 降低CPU负载
-
提高加密性能
-
安全级别分层
- 关键数据:高安全级别
- 一般数据:中等安全级别
- 公开数据:低安全级别
安全开发生命周期¶
安全应该贯穿整个开发过程。
SDL (Security Development Lifecycle):
- 需求阶段
- 安全需求分析
- 威胁建模
-
安全目标定义
-
设计阶段
- 安全架构设计
- 安全机制选择
-
设计审查
-
实现阶段
- 安全编码规范
- 代码审查
-
静态分析
-
测试阶段
- 安全测试
- 渗透测试
-
漏洞扫描
-
部署阶段
- 安全配置
- 密钥管理
-
安全更新机制
-
维护阶段
- 漏洞监控
- 安全补丁
- 事件响应
常见安全误区¶
误区1:隐藏算法可以提高安全性 - 错误:自己发明加密算法 - 正确:使用公开的标准算法,保护密钥
误区2:物理隔离就是安全的 - 错误:认为没有网络连接就安全 - 错误:忽视物理攻击和供应链攻击 - 正确:实施多层防护
误区3:安全是一次性工作 - 错误:产品发布后不再关注安全 - 正确:持续监控、更新和改进
误区4:安全功能可以后加 - 错误:先实现功能,后考虑安全 - 正确:从设计阶段就考虑安全
误区5:只关注外部威胁 - 错误:忽视内部威胁和供应链 - 正确:全面的威胁分析
常见问题¶
Q1: 嵌入式系统安全和IT系统安全有什么区别?¶
A: 主要区别包括:
嵌入式系统特点: - 资源受限(CPU、内存、存储) - 实时性要求高 - 长生命周期(难以更新) - 物理接触风险高 - 专用硬件和协议
IT系统特点: - 资源相对充足 - 可以频繁更新 - 标准化程度高 - 主要面对网络威胁
安全策略差异: - 嵌入式:更依赖硬件安全、轻量级算法 - IT系统:更依赖软件防护、复杂的安全机制
Q2: 如何选择合适的加密算法?¶
A: 选择加密算法需要考虑:
对称加密: - AES:标准选择,硬件支持好 - ChaCha20:软件实现快,适合无硬件加速的场景
非对称加密: - RSA:成熟稳定,但计算量大 - ECC:密钥短,性能好,推荐用于嵌入式
哈希算法: - SHA-256:标准选择 - SHA-3:新标准,更安全
选择建议: - 优先使用标准算法 - 考虑硬件加速支持 - 平衡安全性和性能 - 关注算法的生命周期
Q3: 什么是安全芯片?何时需要使用?¶
A: 安全芯片是专门用于安全功能的硬件模块。
类型: - SE (Secure Element):独立的安全芯片 - TEE (Trusted Execution Environment):CPU内的安全区域 - TPM (Trusted Platform Module):可信平台模块
功能: - 安全密钥存储 - 加密运算加速 - 安全启动 - 防篡改保护
使用场景: - 支付设备 - 身份认证 - 高价值数据保护 - 需要认证的产品
Q4: 如何实现安全的固件更新?¶
A: 安全固件更新的关键要素:
1. 固件签名 - 使用私钥签名固件 - 设备验证签名后才更新
2. 加密传输 - 使用TLS/DTLS加密通道 - 防止中间人攻击
3. 版本控制 - 防止回滚到旧版本 - 记录版本历史
4. 原子更新 - 更新失败能回滚 - 使用双分区或备份
5. 完整性验证 - 下载后验证哈希 - 写入后再次验证
Q5: 如何进行安全测试?¶
A: 安全测试应该包括:
1. 静态分析 - 代码审查 - 使用静态分析工具 - 检查编码规范
2. 动态测试 - 模糊测试(Fuzzing) - 边界测试 - 异常输入测试
3. 渗透测试 - 模拟攻击场景 - 漏洞扫描 - 社会工程测试
4. 硬件测试 - 侧信道分析 - 故障注入 - 物理篡改测试
5. 合规测试 - 标准符合性测试 - 认证测试 - 第三方审计
总结¶
核心要点¶
- 安全威胁多样化
- 物理攻击、软件攻击、网络攻击
- 供应链安全不容忽视
-
需要全面的威胁分析
-
安全需求分析
- CIA三要素:机密性、完整性、可用性
- 使用STRIDE等模型进行威胁建模
-
根据风险确定安全等级
-
安全设计原则
- 纵深防御:多层防护
- 最小权限:限制访问范围
- 默认安全:安全的默认配置
- 故障安全:失败时保持安全
- 开放设计:使用标准算法
-
完全中介:每次都验证
-
安全标准
- 通用标准:ISO 27001、Common Criteria
- 行业标准:ISO 26262、IEC 62443
-
编码标准:MISRA C、CERT C
-
基本防护措施
- 安全启动和固件保护
- 安全通信和密钥管理
- 访问控制和安全日志
- 输入验证和安全编码
实践建议¶
开发阶段: - 从设计开始就考虑安全 - 遵循安全编码规范 - 进行代码审查和测试 - 使用安全开发工具
部署阶段: - 禁用调试接口 - 使用强密码和密钥 - 启用所有安全功能 - 建立安全更新机制
维护阶段: - 持续监控安全事件 - 及时修补漏洞 - 定期安全审计 - 保持安全意识
下一步学习¶
掌握安全概述后,建议继续学习: - 功能安全基础(IEC 61508) - 信息安全基础知识 - 安全启动与固件验证 - 密钥管理与存储 - 安全通信协议实现
延伸阅读¶
推荐书籍¶
- 《嵌入式系统安全》- 全面的嵌入式安全指南
- 《物联网安全》- IoT设备安全实践
- 《密码工程》- 密码学实践应用
- 《安全编码》- 安全编程实践
在线资源¶
- OWASP IoT Project - IoT安全指南
- NIST Cybersecurity - 网络安全资源
- Common Criteria Portal - CC认证信息
- CVE Database - 漏洞数据库
相关文章¶
- 功能安全基础(IEC 61508)- 功能安全标准详解
- 安全启动与固件验证 - 实现安全启动
- 密钥管理与存储 - 密钥安全管理
- 安全通信协议实现 - TLS/DTLS应用
参考资料¶
- ISO/IEC 27001:2013 - 信息安全管理体系
- Common Criteria v3.1 - 信息技术安全评估标准
- NIST SP 800-53 - 安全和隐私控制
- OWASP IoT Top 10 - IoT十大安全风险
- IEC 62443 - 工业自动化和控制系统安全
思考题:
- 分析你正在开发的嵌入式系统,识别主要的安全威胁
- 使用STRIDE模型对系统进行威胁建模
- 评估当前系统的安全等级,制定改进计划
- 设计一个安全启动方案,包括签名验证和防回滚
实践项目:
设计一个物联网设备的安全方案,要求: - 完整的威胁分析 - 安全架构设计 - 安全启动流程 - 安全通信机制 - 密钥管理方案 - 安全更新机制
下一步:建议学习 功能安全基础(IEC 61508)