1. 状态机基础与安全威胁模型

大家好,我是你们的硬件安全讲师。今天咱们聊聊状态机——这个在数字电路里随处可见,却又经常被忽视安全问题的老朋友。

说实话,我做了十几年硬件安全,见过太多因为状态机设计不当导致的严重漏洞。有的能让攻击者直接跳过认证,有的能让系统死锁在某个危险状态。嗯,这些坑我都踩过,今天分享给你们,希望能帮大家少走弯路。

1.1 状态机基本概念

状态机,说白了就是描述系统在不同状态下如何响应输入、如何切换状态的数学模型。你想想看,我们日常用的手机、汽车ECU、甚至智能门锁,底层都是状态机在驱动。

状态机主要分两种:Moore机和Mealy机。我习惯用一句话区分它们——Moore机的输出只看当前状态,Mealy机的输出还看输入。

Moore型状态机

Moore机的特点是:输出只与当前状态有关。举个例子,一个简单的门锁状态机:

// Moore型门锁状态机伪代码
enum State { LOCKED, UNLOCKED, ALARM };

State currentState = LOCKED;

State nextState(Input input) {
    switch(currentState) {
        case LOCKED:
            if (input == CORRECT_PIN) return UNLOCKED;
            if (input == WRONG_PIN) return ALARM;
            return LOCKED;
        case UNLOCKED:
            if (input == TIMEOUT) return LOCKED;
            return UNLOCKED;
        case ALARM:
            if (input == RESET) return LOCKED;
            return ALARM;
    }
}

// 输出只取决于当前状态
Output getOutput() {
    switch(currentState) {
        case LOCKED: return DOOR_CLOSED;
        case UNLOCKED: return DOOR_OPEN;
        case ALARM: return SIREN_ON;
    }
}

我在项目中遇到过,有人把Moore机设计成输出依赖输入,结果综合出来的电路时序全乱了。记住,Moore机的输出寄存器只连状态寄存器,别乱加组合逻辑。

Mealy型状态机

Mealy机的输出则同时依赖当前状态和输入。它通常比Moore机更节省状态数量,但输出容易受输入毛刺影响。

// Mealy型门锁状态机伪代码
State currentState = LOCKED;

Output nextStateAndOutput(Input input) {
    switch(currentState) {
        case LOCKED:
            if (input == CORRECT_PIN) {
                currentState = UNLOCKED;
                return DOOR_OPEN;  // 输出依赖输入
            }
            if (input == WRONG_PIN) {
                currentState = ALARM;
                return SIREN_ON;
            }
            return DOOR_CLOSED;
        // ...
    }
}

核心区别总结:Moore机输出稳定、时序好分析;Mealy机状态少、响应快。安全设计上,我强烈推荐Moore机——输出与输入解耦,天然抗毛刺攻击。

1.2 常见安全漏洞

状态机的安全漏洞,说白了就是攻击者利用设计缺陷,让系统进入非预期的状态或路径。我归纳了三种最常见的类型。

状态跳跃(State Skip)

攻击者通过注入异常输入或时序扰动,让状态机跳过关键状态。比如跳过"认证中"直接进入"已认证"。

我曾经在某个IoT芯片的OTA升级模块里发现过这个问题。攻击者通过电源毛刺,让状态机从"下载固件"直接跳到"执行固件",绕过了签名校验。修复方案是在每个状态转换路径上加硬件看门狗。

死锁(Deadlock)

状态机卡在某个状态无法退出,或者两个状态互相等待。这在多状态机交互时尤其常见。

死锁类型 产生原因 典型案例
单机死锁 状态转换条件永远不满足 等待中断但中断被屏蔽
多机死锁 状态机A等B,B等A 两个外设互等对方释放总线
资源死锁 状态机持有资源A等资源B DMA控制器通道互锁

非法访问(Illegal Access)

攻击者通过非正常路径访问受保护的状态或资源。比如在未授权状态下读取安全密钥寄存器。

为什么会这样?很多设计只检查"当前状态是否允许该操作",但忽略了"从哪个状态来的"。我建议在状态转换路径上也加上权限检查。

1.3 威胁建模方法论

做安全设计,不能等出了问题再补。我习惯在设计阶段就用威胁建模把问题想清楚。这里分享我常用的方法。

STRIDE模型

微软的STRIDE模型,虽然是为软件设计的,但用在硬件状态机上也很顺手:

  • Spoofing(冒充):攻击者伪造合法输入,诱导状态机进入错误状态
  • Tampering(篡改):篡改状态寄存器或转换条件
  • Repudiation(抵赖):状态机没有日志记录,无法追溯攻击
  • Information Disclosure(信息泄露):状态机输出泄露内部状态信息
  • Denial of Service(拒绝服务):通过死锁或状态风暴耗尽系统资源
  • Elevation of Privilege(权限提升):从低权限状态跳跃到高权限状态

我个人习惯:在画状态转换图时,就用不同颜色标注每个状态的安全等级。红色是高危状态(如密钥访问、固件执行),绿色是安全状态(如空闲、休眠)。这样一眼就能看出哪些状态转换路径需要重点保护。

攻击树分析

攻击树是另一种好用的方法。以"绕过认证"为根节点,往下分解攻击路径:

绕过认证
├── 状态跳跃攻击
│   ├── 电源毛刺注入
│   ├── 时钟毛刺注入
│   └── 电磁干扰
├── 状态寄存器篡改
│   ├── 激光故障注入
│   ├── 电压故障注入
│   └── 软件漏洞利用
└── 状态转换条件绕过
    ├── 输入验证绕过
    ├── 时序攻击
    └── 侧信道分析

每个叶子节点对应一种具体的攻击手段。设计时,针对每个叶子节点都要有对应的防护措施。

安全状态机设计原则

基于上面的威胁模型,我总结了几条铁律:

  1. 最小权限原则:每个状态只允许访问它需要的资源。别让"空闲"状态也能读写密钥寄存器。
  2. 状态转换验证:每个状态转换都要做完整性检查。我习惯用CRC校验状态转换路径。
  3. 看门狗机制:每个状态都要有超时退出机制。防止攻击者把状态机卡在某个状态。
  4. 冗余状态编码:别用简单的二进制编码。用格雷码或One-Hot编码,天然抗单粒子翻转。
  5. 安全状态隔离:高危状态和普通状态用硬件隔离,比如不同的电源域或时钟域。

记住:安全不是加功能,而是减风险。好的状态机设计,应该让攻击者"想跳跳不了,想卡卡不住,想看看不到"。

1.4 知识体系总览

下面这张图是我画的本章知识体系,方便大家建立整体认知:

状态机安全设计知识体系 状态机基础 • Moore型状态机 • Mealy型状态机 • 状态转换图 • 输出逻辑设计 • 时序约束 安全威胁模型 • 状态跳跃攻击 • 死锁攻击 • 非法访问 • 故障注入 • 侧信道分析 防护设计方法 • STRIDE模型 • 攻击树分析 • 最小权限原则 • 看门狗机制 • 冗余状态编码 核心目标:让攻击者"想跳跳不了,想卡卡不住,想看看不到"

这张图把本章内容串起来了。左边是基础,中间是威胁,右边是防护。三者缺一不可。你想想看,不懂基础就谈安全,那是空中楼阁;不懂威胁就谈防护,那是闭门造车。

我建议:学完本章后,拿你手头的一个简单状态机(比如UART接收状态机),用STRIDE模型过一遍,看看能发现几个安全漏洞。实践出真知。

好了,第一章就到这里。记住,状态机安全设计不是事后补丁,而是从架构设计阶段就要考虑的事情。下一章我们深入讲状态编码的安全设计,到时候见。

可可精品资料库