ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

嵌入式设备出厂安全:先御OS四道闸门与迁移落地

嵌入式设备出厂安全:先御OS四道闸门与迁移落地 1. 出厂即“裸奔”的嵌入式设备风险到底藏在哪几层前年冬天我帮一家做边缘网关的团队做交付前的安全预检。两千台设备已经装箱客户的甲方安全团队抽了三台出来扫结果两天后发回一份报告固件包未签名、调试串口在成品上没关、系统里还躺着一个默认口令的调试账号、日志目录权限是 777、升级包用 HTTP 明文下发。整批货在仓库里扣了四十天返工成本比整机的物料成本还高。这件事之后我形成了一个习惯任何嵌入式项目在打样阶段就要把“出厂状态”当成一个独立的需求项来对待而不是等到量产前一周才想起来加固。嵌入式设备之所以容易“裸奔”跟它的开发逻辑有直接关系。做嵌入式的人从第一天起追的是三件事能跑起来、跑得稳、成本低。开发板上串口一插、root 一登、想改什么改什么这种“完全敞开的便利”会一路带到量产固件里因为没人会在交付前专门做一次“反向清理”。而通用服务器领域早就有成熟的加固清单、基线扫描、镜像签名流程嵌入式这边往往还停留在“板子能亮就是成功”的阶段。“先御OS”这个思路的核心是把原本靠事后补救的安全能力挪到操作系统这一层做成出厂默认值——设备一上电可信启动、权限收敛、行为审计、基线策略都已经在位。换句话说不需要每家企业自己重新发明一遍加固流程系统本身就带着一套可复用的安全底座。下面我按自己实际踩过的路把这套东西拆开讲。1.1 从启动链看谁在给谁放行启动链是嵌入式安全里最容易被忽视、又最难事后补救的一层。一块典型的 ARM 板子上电之后的顺序是芯片内部 ROM 代码 → 一级引导通常是片上固化的→ 二级引导U-Boot 之类→ 内核 → 根文件系统。问题出在中间这几段大多数量产设备把二级引导和内核镜像放同一个未做校验的分区里任何人只要能物理接触板子、或者从升级通道塞一个包进去就能把整个系统换掉而且换完之后设备照样正常启动外观上完全看不出异常。我在一个电力监测项目上见过更隐蔽的版本厂家确实做了校验但校验值写在同一块 SPI Flash 的明文分区里攻击者改完固件顺手把校验值一起改了等于没做。这类问题在“裸奔”设备里非常普遍因为开发者做校验的动机往往只是“防误刷”而不是“防篡改”两者的强度要求差了一个数量级。可信启动的意义在于把信任锚点锁死在芯片内部不可改的 ROM 里每一级都校验下一级校验不通过就不放行。它的代价是要额外占用一点启动时间还要处理密钥烧写的产线流程。先御OS 在这一层的做法是把信任链和密钥管理做成标准件产线只需要在烧录环节注入一次设备密钥后面的签名、校验、失败回退都由系统自身处理不需要每个项目组自己写一套 bootloader 校验代码。1.2 从运行态看默认口令与开放调试口运行态的问题更直观也更容易被自动化扫描工具抓到。我梳理过一批被退回的固件出现频率最高的几项几乎每次都一样调试用的 telnetd 或者临时 sshd 没删Web 管理页面的初始口令是 admin/admin 或者空口令串口控制台在成品状态下仍然可登录内核命令行里带着consolettyS0和init/bin/sh这类调试参数文件系统里残留着编译机的路径和符号表。这些东西在开发阶段都是“方便”到了客户手里就变成“后门”。尤其是串口很多设备外壳上就留着一个四针排针一把 USB-TTL 就能拿到 root shell连拆机都省了。有没有必要在量产固件里保留这些能力我的判断标准很简单这个接口在设备的整个生命周期里业务上是否真的需要被外部访问如果只是研发和售后调试用那就应该做成受控进入的方式而不是常开。先御OS 在这一层的思路是把“权限”和“可达性”从应用代码里抽出来交给系统统一管。默认策略里调试类服务处于关闭状态需要凭签名的调试授权文件才能临时开启并且开启行为会被记录进审计日志。这样一来售后仍然能修问题但“谁能开、开了多久、开了做什么”是可追溯的。1.3 从交付看补丁与审计的断档第三层问题出在交付之后。嵌入式设备一旦出厂往往就进入了长达五到十年的“失联”状态没有升级通道或者有升级通道但没有签名校验或者有升级但现场没人敢推。与此同时客户的安全团队却需要一个能证明“这台设备是受控的”的东西——日志、版本清单、配置基线、变更记录。我见过最尴尬的场景是客户要一份设备侧的操作审计记录厂家只能拿出开发群里的一句“我们没记日志”。这不是技术能力问题是设计阶段就没把审计当成交付物。审计日志在嵌入式上的难点很实际存储小、写入寿命有限、掉电可能丢数据、时间戳可能不准。所以它不是“打开 syslog 就完事”需要专门做存储策略、轮转策略、掉电保护和时钟同步。“裸奔”项典型表现现场后果启动链无校验引导、内核、根文件系统均可替换设备被改成任意系统无感知默认口令admin/admin、空口令、固定调试账号被扫描工具批量识别横向渗透调试口常开串口可登 root、telnetd 未删物理接触即完全接管升级无签名HTTP 明文下发 tar 包中间人替换固件无审计日志无操作记录、无时间戳出事后无法定责客户审计不通过配置无基线每台设备参数不一致批量运维失控问题难以复现这张表我给不少团队看过大多数人第一反应是“这些我们都知道”但第二反应是“真去查一遍至少中三条”。这就是现状。2. 先御OS 的“合规免疫”不是加壳而是四道闸门很多人第一次听到“出厂即带合规免疫”这个说法会以为是给系统套了一层加密壳或者装了个安全组件。实际拆开看它更像是把四类彼此独立的能力预先装进系统并且让它们默认就是开启状态。这四类能力分别管的是东西是不是真的完整性、能做什么权限、做过什么审计、按什么规则做策略。四者缺一不可只做其中一个防护效果会大打折扣。举个具体的例子只做完整性校验不做权限收敛攻击者不需要改固件直接用合法进程的漏洞就能干坏事只做权限收敛不做审计出了问题你只知道“被限制了”不知道“谁在什么时候尝试了什么”只做审计不做策略基线日志里全是噪音真正有价值的记录被淹没。四道闸门是相互咬合的。2.1 第一道闸可信启动与固件完整性度量可信启动解决的是“信任起点”的问题。它的实现方式通常是芯片内 ROM 中固化一段只读代码用内置的公钥校验一级引导一级引导校验二级引导二级引导校验内核和设备树内核挂载根文件系统前校验其哈希。每一级的公钥或者哈希都来自上一级的可信存储链条一旦断开就停止启动或者进入恢复模式。在嵌入式上落地这一层有几个实操细节值得单独说。一是密钥的存放最好放在芯片的 OTP 区或者独立的安全存储里而不是普通的 Flash 分区普通分区可以被擦写等于信任锚点可以被搬走。二是签名算法要跟芯片能力匹配低端 MCU 上跑 RSA-2048 校验可能要几百毫秒ECDSA P-256 会快很多但要确认硬件加速器支持。三是启动失败的降级策略必须提前定义是直接停机、还是进入只读的恢复系统、还是允许一次带记录的降级启动这三种选择在不同业务里的可接受度完全不同。先御OS 在这一层把“度量”和“校验”分开处理校验是硬性的不过不放行度量是把每一级的哈希值记录下来形成一个可上报的证据链。这个区分很关键因为有些现场场景下你没法强制校验比如客户要求必须能刷第三方固件但度量仍然可以做至少能留下记录。2.2 第二道闸最小权限与能力白名单权限收敛的目标是让每个进程只能碰到它真正需要碰的东西。传统嵌入式系统的做法是“所有业务都跑在 root 下”因为改起来最省事。但一旦某个网络服务被攻破攻击者拿到的就是整台设备。具体落地上有三个层次。第一层是进程账号分离把网络服务、数据采集、本地界面、升级组件拆到不同账号下运行各自只拥有自己那部分文件的读写权限。第二层是能力capability裁剪需要绑定低端口的进程只给CAP_NET_BIND_SERVICE需要操作原始套接字的只给CAP_NET_RAW而不是给全量 root 权限。第三层是系统调用过滤把进程实际用到的系统调用列出来做成白名单超出范围的调用直接拒绝。第三层在嵌入式上争议比较大因为有些库在运行时会动态加载、间接调用很多系统调用白名单做窄了会运行时报错做宽了等于没做。我的经验是先跑一周的“学习模式”把所有实际发生的系统调用记录下来人工筛掉明显不该出现的比如 execve、ptrace再固化成白名单。这个过程不能省否则上线的第一天就会收到一堆莫名其妙的崩溃反馈。2.3 第三道闸行为审计与不可篡改日志审计日志在嵌入式上有两个硬约束存储小、写入寿命有限。一块 eMMC 或者 SPI NAND 的擦写次数是有上限的如果每秒往日志文件里写几条记录几年下来存储先坏。所以审计策略必须做得克制——记录“关键动作”而不是“所有动作”。我通常建议至少记录这几类事件账号登录与切换、调试接口的开闭、配置项的修改、固件升级的发起与结果、策略拒绝事件、系统异常重启。这几类事件加起来正常运行的设备一天也就几条到几十条对存储压力很小但出问题的时候信息量足够。不可篡改是第二个要点。如果日志能被写入者自己删掉审计就没有意义。常见做法是链式哈希每条记录带上一条记录的哈希值形成链再定期把链头哈希写入受保护的存储或者上报到平台。这样删掉中间某条记录链就断了一验就知道。2.4 第四道闸策略引擎与出厂预置基线策略引擎负责把上面三件事的规则统一起来管并且支持按设备型号、按批次、按客户下发不同的策略包。这里最重要的不是引擎本身有多复杂而是“出厂预置基线”这个概念——设备在没有任何外部管理平台接入的情况下也应该有一套可用且合理的默认策略。很多项目死在这一点上策略全部依赖云端下发结果设备部署在没有外网的环境里等于裸奔。先御OS 的做法是把基线策略固化进镜像云端策略只是“增量调整”这样即使设备永远不联网基础的安全姿态也是成立的。这个设计取舍看起来很朴素但在实际交付里价值极高。闸门管什么典型失效场景可信启动固件是否被替换校验值与被校验对象同分区存储最小权限进程能碰到什么业务全跑 root一处失守全线失守行为审计谁做了什么日志可被业务进程自行删除策略基线按什么规则执行策略全部依赖云端离线即失效3. 把老平台迁到先御OS一次可复现的落地流程迁移这件事最怕的是把它当成“换系统”。它不是换系统是在原有业务逻辑外面重新包一层运行时约束。我做过几次类似的迁移总结下来顺序很重要先摸清现状再规划分区再适配外设最后才是出厂烧录。顺序搞反了返工量会翻倍。3.1 迁移前的三张清单第一张是进程清单设备上到底有哪些进程在跑分别在什么权限下跑监听哪些端口读写哪些路径。这张清单不用工具也能列但一定要列出来因为它决定了权限拆分的颗粒度。可以用ps -eo pid,user,comm,args和ss -tulnp组合跑一整天把出现过的进程都记下来。第二张是文件清单哪些目录需要持久化、哪些可以只读、哪些是临时目录、哪些是升级时会被替换的。持久化和只读的划分直接决定分区规划。我的经验是根文件系统能做成只读就做成只读持久数据挂到单独的可写分区临时文件挂 tmpfs。第三张是接口清单设备对外有哪些物理和逻辑接口分别是给谁用的、开放到什么程度、有没有认证。串口、USB、网口、蓝牙、本地调试口都要写清楚并且明确标注“量产时是否保留”。3.2 镜像裁剪与分区规划分区规划我不建议照抄别人的模板因为它跟升级方案强绑定。一个比较常见的结构是这样分区内容挂载方式说明bootloader一级/二级引导不挂载校验由 ROM 完成kernel内核 设备树只读启动时校验哈希rootfs-a / rootfs-b根文件系统双备份只读升级时交替写入data业务数据与配置读写加密可选log审计日志追加写独立分区限制配额recovery恢复系统只读前两个 rootfs 都校验失败时进入双 rootfs 的价值在于升级时可以“先写备用分区、校验通过再切换”切换失败还能回退。代价是存储翻倍对于 Nor Flash 只有 16MB 的设备就不现实了那种情况要考虑差分升级包或者压缩镜像。裁剪方面我的原则是“删掉所有非必需的服务和工具”包括 shell 里的多余命令、包管理器、编译器、调试符号。留一个 busybox 够用就行。这一步做完攻击面会小一大截镜像也能小 30% 往上。3.3 策略下发与外设适配策略下发有两种模式内置基线 本地配置文件和内置基线 平台远程下发。前者适合离线设备后者适合有统一运维平台的场景。实际项目里往往是混合的出厂带基线上线后由平台做个性化调整。外设适配是迁移里最容易卡住的地方。摄像头、传感器、加密芯片、4G 模组这些设备节点往往需要特定的权限才能访问。如果权限模型收得太紧业务进程就会报“Permission denied”而且报错位置常常离真正的原因很远。我的做法是先把外设节点全部列出来配上对应的设备规则再逐个放开到刚好够用# 列出当前被访问的设备节点用于确定规则范围 ls -l /dev/ | grep -E video|tty|i2c|spi|mmcblk|gpio # 查看某个业务进程实际打开了哪些设备 ls -l /proc/$(pidof sensor_service)/fd | grep /dev3.4 出厂烧录与首次上电自检产线烧录阶段要解决的是“密钥注入”和“状态清零”。密钥必须在产线注入并且每台唯一不能所有设备共用一把状态清零指的是把开发阶段遗留的调试账号、临时文件、历史日志全部清掉让设备出厂时是一个干净的可信状态。首次上电自检我建议做成一个固定流程并输出到日志校验引导链、校验内核与根文件系统、检查策略是否加载成功、检查审计服务是否运行、检查存储配额是否生效。这五项任意一项失败就应该在设备上有明确的指示比如状态灯特定闪烁序列而不是静默继续运行。产线上如果只测“能开机”那这批设备的安全姿态实际上是没有保证的。4. 策略配置的颗粒度怎么做到“既管得住又不误伤”策略的难点从来不是“能不能配”而是“配到什么程度”。收得太松等于没做收得太紧业务跑不起来。我的判断标准是任何一条策略都应该能回答“它拦截的是什么风险”和“它影响了什么业务”这两个问题回答不上来的策略要么删掉要么重写。4.1 白名单的三种收敛方式白名单有三种常见的收敛路径各有适用场景。第一种是路径白名单限定进程只能读写特定目录。上手最快改动最小适合改造存量项目。缺点是防不住“合法目录内的非法操作”比如某进程本来只读配置但配置目录是可写的它就能改自己的配置。第二种是可执行文件白名单限定只能运行特定二进制并且校验其哈希。这个强度高很多能挡住大量通过落地脚本实现的攻击。代价是任何一次小的二进制更新都要重新计算哈希并下发运维流程要跟上。第三种是系统调用白名单限定进程能用的系统调用集合。强度最高但也最脆弱内核升级、库更新、编译器优化都可能改变调用模式。我只建议在安全要求极高、且业务逻辑非常稳定的场景下使用。实际项目里我一般用“路径白名单打底 可执行文件白名单做关键进程”的组合系统调用白名单留给少数核心服务。4.2 审计日志的存储与轮转日志分区独立出来之后还要做三件事配额、轮转、掉电保护。配额是给日志分区一个固定大小比如 64MB写满之后要么覆盖最旧记录要么停止写入。这里有个取舍停止写入能保护旧证据但新事件会丢失覆盖旧记录能持续记录但老证据会被冲掉。我的做法是分级——关键事件升级、登录、策略变更单独存到一个不轮转的小分区普通事件走轮转分区这样关键证据不会被冲掉。掉电保护是指写入必须考虑突然断电。日志采用追加写加校验和的方式一条记录写完再更新索引恢复时从头扫描遇到校验失败的尾部记录直接丢弃。这样最坏情况只丢最后一条不会整个文件损坏。4.3 升级与回滚链路的策略设计升级链路是安全上最敏感的一段因为它天然需要写权限而写权限一旦被滥用就能改掉整个系统。我的设计原则是升级组件只做“搬运和校验”不做“决定”。也就是说升级组件负责接收升级包、校验签名、写入备用分区是否切换、何时切换、切换失败怎么办由引导程序在重启后决定。# 升级包校验的典型流程示意 verify_signature upgrade.bin pubkey.pem || exit 1 sha256sum -c upgrade.bin.sha256 || exit 1 write_to_partition rootfs-b upgrade.bin || exit 1 mark_boot_target rootfs-b sync reboot回滚要预设条件新系统启动后如果在规定时间内没有完成自检上报引导程序自动切回原分区。这个“规定时间”不能太长否则设备会卡在半死状态也不能太短否则正常的慢启动会被误判。我一般设在 90 秒到 3 分钟之间具体看业务启动耗时。5. 实测中最容易翻车的五个点这一节是我自己踩过的坑不是理论风险。每一个都真实发生过而且都是在“测试环境没问题、现场批量出问题”的情况下出现的。5.1 启动耗时被低估可信启动要逐级校验校验大镜像比如几百兆的根文件系统在低端处理器上可能要好几秒。我们在一个项目上测算过加上完整校验之后启动时间从 8 秒涨到 19 秒。对于需要快速上线的工业设备这个延迟是不可接受的。解决办法有两个方向。一是只对根文件系统的关键部分做哈希树校验而不是整块校验可以边加载边校验二是把校验结果缓存到受保护的存储里下次启动只要缓存有效就跳过只校验缓存本身的签名。第二个办法快但要注意缓存的失效条件必须严谨否则等于没校验。5.2 外设驱动与权限模型打架有一次权限模型上线后4G 模组随机掉线日志里只有一句“open /dev/ttyUSB2 failed”。排查了两天才发现是设备节点规则匹配顺序问题模组热插拔后重新生成的节点属主变了而规则里只按固定的属主匹配。这类问题在测试阶段不容易暴露因为测试时设备节点是稳定的现场热插拔一多就出问题。经验是设备规则尽量按“设备类型 子系统”匹配少按固定路径或固定属主匹配热插拔场景一定要做循环插拔测试至少一百次。5.3 日志把存储写爆审计服务上线后的第一周某型号设备的日志分区就写满了原因是某个进程在异常循环里反复触发策略拒绝事件每条都记了日志。后来我们加了速率限制同一事件类型在单位时间内只记一次摘要超出部分只累加计数。这件事的教训是审计策略必须考虑“异常情况下的写入量”而不是只按正常情况估算。任何能被外部输入触发的事件都要有速率限制。5.4 OTA 与完整性校验的互锁升级包本身要签名升级后的系统要校验如果两者的密钥体系没打通就会出现“包验过了、系统起不来”的尴尬。我遇到过一次升级包的签名用的是产线密钥系统启动校验用的是设备密钥结果升级成功但重启后校验失败进了恢复模式。整整一批设备需要返厂。解决办法是把密钥体系设计成层次结构——根密钥签产线密钥产线密钥签设备密钥升级时用产线密钥签包设备用自己的设备密钥验两者通过证书链关联。设计阶段多花两天能省掉后面的灾难。5.5 时钟与时间戳失真导致审计断链嵌入式设备大多没有 RTC 电池上电后系统时间是默认值比如 1970 年等联网后才同步。这段时间里产生的审计记录时间戳全是错的事后根本没法还原事件顺序。更麻烦的是链式哈希如果按时间排序时间回跳会导致链的顺序混乱。我的做法是引入一个单调递增的计数器审计记录同时带“单调序号”和“墙钟时间”。排序和验链用单调序号人类阅读用墙钟时间两个都保留。首条记录额外标注“时间未同步”避免误导。6. 什么样的项目适合上先御OS什么样的别硬上技术方案没有普适性我想把适用边界说清楚省得有人照搬之后发现不匹配。6.1 高适配场景第一类是有明确交付安全要求的设备比如客户在合同里写了安全基线条款或者设备的部署环境本身要求受控。这类场景下安全能力是交付物的一部分不做反而过不了验收。第二类是长期无人值守、且物理上可接触的设备比如户外机柜、充电桩、工业现场的采集终端。这类设备一旦被物理接触没有可信启动和权限收敛基本等于完全敞开。第三类是批量出货、需要统一运维的型号。设备数量一上来靠人工逐台加固是不现实的必须有出厂预置基线加统一策略下发。第四类是有升级需求但升级通道本身是风险点的设备。只要涉及 OTA签名校验和回滚机制就是必需品不是可选项。6.2 需要谨慎评估的场景第一类是资源极度受限的 MCU 级设备比如只有几十 KB RAM 的单片机。完整的可信启动和审计栈跑不起来这时候应该退而求其次只做最关键的几项比如固件签名校验和唯一密钥别硬套完整方案。第二类是启动时间有硬性约束的设备比如需要在几百毫秒内响应的控制系统。这时候要重新设计校验策略做增量校验和缓存或者把安全校验挪到非关键路径上异步执行。第三类是业务逻辑还在快速迭代、二进制频繁变更的早期项目。这时候上严格的白名单策略维护成本会超过收益。可以先把可信启动和审计上起来权限策略等业务稳定后再逐步收紧。第四类是已有完整安全体系且经过验证的存量平台。这种情况下引入新系统要评估迁移风险不要为了“带免疫”而把一套稳定运行的系统推倒重来。场景特征建议动作理由有合同安全条款全量启用安全是交付物无人值守且可物理接触至少启用可信启动 权限收敛物理接触是最强攻击面批量出货启用出厂基线 平台策略人工加固不可行涉及 OTA启用签名校验 双分区回滚升级通道本身是风险点MCU 级资源受限只做固件签名 唯一密钥完整方案跑不动启动时间硬约束增量校验 缓存全量校验延迟不可接受业务频繁迭代先上可信启动与审计权限后收白名单维护成本过高最后分享一个我在多个项目里反复验证过的小技巧不要试图一次把策略收紧到位而是先在“只记录不拦截”的模式下跑两到四周把实际发生的访问行为全量收集下来再基于真实数据生成白名单。这样出来的策略收敛程度往往比拍脑袋定的规则严格得多而且几乎不会误伤业务。我最早做权限收敛的时候图快直接照文档写规则结果上线第一周收到了三十多份现场故障单全是权限被拒导致的。后来改成先观察再收敛同样的项目故障单降到了个位数。这个顺序上的调整比换任何工具都管用。
返回列表