ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

嵌入式合规从操作系统层破局:ARM平台安全加固与审计实践

嵌入式合规从操作系统层破局:ARM平台安全加固与审计实践 1. 嵌入式合规这道坎为什么总在操作系统层翻车做嵌入式这行的朋友大概都经历过这样的场景产品功能跑通了样机也稳定了结果卡在合规审查上被要求补一堆安全基线、审计日志、权限隔离的材料。回头一看底层系统是个裁剪过的老内核连基本的强制访问控制都没开应用层再怎么打补丁也是治标不治本。这个问题的根子在于很多团队把嵌入式设备当成功能机来做——只要能跑起来、能通信、能控制外设就行操作系统层面能省则省。但现在的合规要求早就不是查你有没有防火墙那么简单了它要的是从内核到应用的一条完整信任链。你应用层做得再漂亮底层是个裸奔的系统审查一样过不去。我接触过不少做工业网关、边缘计算盒子的团队他们的典型做法是拿一份厂商提供的BSP包删掉不需要的组件编译出一个能跑的最小系统。这种做法在功能验证阶段没问题但到了量产和合规阶段就会暴露三个致命短板第一内核配置没有安全加固很多危险的调试接口还开着第二没有完整的包管理机制补丁升级全靠手动替换文件第三缺少统一的身份认证和访问控制框架每个应用各管各的。所以标题里说的从操作系统解决不是一句口号而是说要把合规能力下沉到系统层让上层应用天然就运行在一个合规的底座上。这就像盖房子你装修再豪华地基没打牢验收的时候照样通不过。1.1 合规到底在查什么别自己吓自己很多刚接触合规的开发者一听到等保安全基线就头大觉得要改的东西太多。其实拆开来看嵌入式设备要过的合规检查核心就四类访问控制谁能登录、能执行什么命令、能访问哪些文件必须有明确的策略不能是默认全开。审计追溯系统里发生了什么关键操作要有日志记录而且日志不能被随意篡改或删除。完整性保护系统启动过程、关键配置文件、可执行程序要能检测是否被篡改。最小化原则不需要的服务、端口、账号、软件包统统关掉或删掉减少攻击面。这四类要求如果放在应用层做每个应用都要重复实现一遍而且很容易有遗漏。但如果放在操作系统层通过内核的安全模块、系统的包管理、统一的认证框架来解决就是一次配置、全局生效。我见过一个做智能终端的团队最开始是在每个应用里自己写权限校验结果三个应用三种写法审查的时候被指出策略不一致。后来他们把权限控制统一收到系统的强制访问控制模块里应用只需要声明自己需要什么权限由系统来裁决不仅审查过了代码还少了一大截。1.2 为什么是操作系统层而不是应用层这里要讲清楚一个逻辑合规的本质是可证明的安全不是我觉得安全。应用层的安全措施审查方很难验证你是不是真的生效了因为每个应用的实现方式都不一样。但操作系统层的安全机制是有标准接口和标准配置的审查方可以通过检查系统配置、查看内核参数、读取审计日志来验证。举个例子你要证明只有授权用户能访问某个配置文件如果在应用层做你得展示代码逻辑、测试用例、异常处理。但如果在系统层用文件权限加访问控制策略来做审查方只需要看一条策略配置就知道结果了。这就是把合规能力下沉到操作系统的价值——让安全变得可配置、可验证、可审计。另外还有一个现实原因嵌入式设备的生命周期很长应用可能会换、会升级但操作系统相对稳定。把合规能力放在系统层应用迭代的时候不需要重新做合规验证只要系统基线没变合规状态就保持有效。这对产品维护来说省的是长期的人力成本。2. 选对操作系统底座合规就成功了一半既然要在操作系统层解决合规问题那选哪个系统就成了第一个关键决策。嵌入式领域常见的选项有裸机、RTOS、以及各种Linux发行版。裸机和RTOS在功能安全场景有优势但在通用合规场景下生态和工具链的成熟度往往不够。所以大多数需要过合规的嵌入式设备最终还是会落到Linux系上。但Linux发行版那么多从Ubuntu到Debian从Yocto到Buildroot再到国产的openEuler怎么选我的经验是看三个维度安全机制的完备性、包管理和升级能力、以及社区或厂商的长期维护承诺。2.1 主流嵌入式Linux方案的合规能力对比先上一张我自己整理的对比表这些都是实际项目中踩过坑之后总结的方案安全机制包管理升级方式合规适配难度Buildroot需自行配置内核安全选项无原生包管理整镜像替换高全靠自己Yocto支持SELinux/AppArmor有包管理但复杂分层升级中高学习曲线陡Ubuntu Core自带AppArmor和快照snap包管理原子升级中但定制受限openEuler支持SELinux、完整性度量rpm/dnf支持增量升级中低文档较全Debian支持AppArmor/SELinuxapt/dpkg常规升级中但嵌入式裁剪需功夫从合规角度来说openEuler这两年在嵌入式方向的投入值得关注。它本身是从服务器场景发展来的安全机制比较完整SELinux、审计、完整性度量这些都有现成支持而且包管理用的是rpm/dnf体系升级和补丁管理比较规范。对于需要过合规的嵌入式设备来说这些特性直接省掉了大量自己造轮子的工作。当然选型不是绝对的。如果你的设备资源极其受限比如只有几十兆内存那可能还是得用Buildroot自己裁剪。但如果资源允许我建议优先考虑安全机制完备的发行版因为合规这件事自己从头做真的不划算。2.2 为什么ARM平台是合规嵌入式的主流选择热词里反复出现ARM这不是偶然。现在做嵌入式设备ARM架构几乎是默认选项原因很简单功耗低、生态成熟、芯片选择多。从Cortex-A系列跑Linux到Cortex-M系列跑RTOS覆盖了从低端到高端的全部场景。但ARM平台做合规有个特殊点启动链的完整性验证。ARM的启动流程通常是BootROM加载SPLSPL加载U-BootU-Boot再加载内核。这条链上任何一环被篡改整个系统的可信基础就没了。所以合规要求高的设备通常要在BootROM阶段就启用安全启动逐级验证签名。这个机制在ARM平台上是有标准实现的比如ARM Trusted Firmware就提供了完整的可信启动框架。但很多团队做嵌入式开发时为了调试方便会把安全启动关掉量产时又忘了打开结果合规审查时被查出启动链没有验证。这种坑我见过不止一次后面会详细讲怎么排查。2.3 国产化需求下的操作系统选择思路热词里出现了linux国产openeuler安装这些词说明国产化是一个真实的需求场景。在国产化要求下操作系统选型通常要考虑几个因素是否有国内厂商的长期维护、是否适配国产芯片、是否有完整的合规认证材料。openEuler在这方面的优势是生态相对开放支持多种国产ARM芯片而且社区活跃文档和工具链比较全。我实际在ARM服务器和嵌入式板子上都部署过openEuler安装过程和常规Linux发行版差别不大但安全相关的默认配置比很多通用发行版要严格这对合规来说是个加分项。不过要注意openEuler的嵌入式适配和服务器版本还是有差异的有些板子的BSP需要自己适配。我的建议是如果选openEuler做嵌入式先确认目标芯片有没有现成的镜像或BSP支持没有的话要预留足够的适配时间。3. 从内核到应用合规能力怎么一层层搭起来选好底座之后接下来就是具体的搭建工作。这部分我按启动链、内核、系统服务、应用四个层次来讲每一层都有对应的合规要点和实操方法。3.1 启动链的可信验证怎么配启动链验证是合规的第一道门。它的逻辑是每一级启动程序在加载下一级之前先验证下一级的数字签名验证通过才继续不通过就停止启动或进入恢复模式。在ARM平台上这个流程通常是这样实现的BootROM阶段芯片出厂时固化的代码验证第一级引导程序的签名。这一步通常由芯片厂商提供开发者能配置的是公钥哈希。SPL/U-Boot阶段验证内核和设备树的签名。U-Boot支持FIT镜像格式可以把内核、设备树、签名打包在一起。内核阶段验证根文件系统的完整性通常用dm-verity机制。实操中配置U-Boot的签名验证需要生成密钥对、签名镜像、把公钥烧到设备里。这个过程听起来简单但有几个坑注意签名密钥一旦丢失设备就无法启动所以密钥的备份和管理要有严格流程。我见过团队把密钥放在开发机上结果开发机重装系统后密钥没了所有设备变砖。还有一个常见问题是调试阶段为了方便会关闭验证但量产固件忘记重新打开。我的做法是在构建脚本里加一个检查如果构建的是release版本就强制要求签名验证开启否则构建失败。这样从流程上避免人为疏忽。3.2 内核安全配置的必选项和可选项内核是操作系统的核心也是合规检查的重点。Linux内核提供了大量的安全配置选项但默认配置通常是为了兼容性很多安全功能是关闭的。做合规嵌入式需要根据设备场景打开相应的选项。必选项我列一下这些是合规审查基本都会看的CONFIG_SECURITY启用安全框架这是其他安全模块的基础。CONFIG_SECURITY_SELINUX或CONFIG_SECURITY_APPARMOR强制访问控制二选一即可SELinux更严格但配置复杂AppArmor相对易用。CONFIG_AUDIT审计子系统记录系统调用和文件访问。CONFIG_INTEGRITY完整性子系统配合dm-verity或IMA使用。CONFIG_STRICT_KERNEL_RWX内核代码段只读、不可执行防止代码注入。CONFIG_STACKPROTECTOR栈保护防止缓冲区溢出攻击。可选项根据设备场景来定比如如果设备有网络功能CONFIG_NETFILTER和相关防火墙模块要开。如果设备处理敏感数据CONFIG_CRYPTO相关的加密算法要配置齐全。如果设备支持调试接口**CONFIG_DEBUG_**系列要谨慎量产固件应该关闭大部分调试选项。配置内核的时候我习惯用make menuconfig逐项检查而不是直接用一个默认配置。因为默认配置里往往开着很多不需要的驱动和功能既增加攻击面又浪费资源。裁剪的原则是只保留设备实际用到的功能其余全部关闭。3.3 系统服务的最小化与访问控制内核配好之后接下来是系统服务。嵌入式设备常见的做法是跑一个精简的init系统然后启动必要的服务。合规要求这里的关键是最小化——不需要的服务一个都不跑。我通常的做法是先列出设备必须的功能然后反推需要哪些服务。比如一个工业网关必须的功能是网络转发、数据采集、远程管理那对应的服务就是网络配置、采集程序、管理代理其他像打印服务、蓝牙服务、图形界面统统不装。访问控制方面SELinux或AppArmor的策略要针对每个服务定制。这里有个经验不要一开始就追求完美的策略先用宽容模式跑一段时间收集实际的访问行为再逐步收紧。直接上强制模式很容易导致服务起不来排查起来很痛苦。# 查看SELinux当前模式 getenforce # 临时切换到宽容模式 setenforce 0 # 查看审计日志中的拒绝记录 ausearch -m avc -ts recent上面这几条命令是我调试SELinux策略时最常用的。先看当前模式需要调试时切到宽容模式然后通过审计日志看哪些访问被拒绝了据此调整策略。等策略稳定了再切回强制模式。3.4 应用层的合规接口怎么设计操作系统层的能力搭好之后应用层要做的是对接而不是重复实现。也就是说应用不需要自己写权限校验、自己写日志记录而是调用系统提供的标准接口。比如身份认证应用不应该自己维护用户密码而是通过PAM可插拔认证模块来对接系统的认证机制。这样用户的账号、密码策略、登录限制都由系统统一管理应用只管调用。再比如审计应用不需要自己写日志文件而是通过audit框架上报关键事件。这样所有日志格式统一审查方可以通过ausearch等工具统一查询。这种设计的好处是合规能力集中在系统层应用开发只需要关注业务逻辑。而且当合规要求变化时只需要调整系统配置不需要改应用代码。我做过一个项目从等保二级升到三级因为合规能力都在系统层只花了几天调整配置就完成了应用代码一行没动。4. 实操在ARM板子上搭一个合规就绪的系统前面讲的是思路和原理这一节讲具体怎么做。我以一块常见的ARM开发板为例从零开始搭一个合规就绪的嵌入式系统。这里不涉及具体厂商只讲通用流程。4.1 环境准备与工具链配置首先需要准备交叉编译环境。ARM平台的交叉编译工具链有几种选择厂商提供的、Linaro的、或者用Buildroot/Yocto自动生成的。我一般用厂商提供的工具链因为对特定芯片的优化更好。# 解压工具链 tar -xf gcc-arm-xxx.tar.xz -C /opt/ # 设置环境变量 export PATH/opt/gcc-arm-xxx/bin:$PATH export CROSS_COMPILEarm-linux-gnueabihf- export ARCHarm # 验证工具链 arm-linux-gnueabihf-gcc --version环境变量设置好之后编译内核和U-Boot时就会自动使用交叉编译器。这里要注意CROSS_COMPILE的值要和工具链的前缀一致不同厂商的工具链前缀可能不同有的是arm-linux-gnueabihf-有的是arm-none-linux-gnueabi-搞错了会编译失败。4.2 内核裁剪与安全选项配置内核配置是重头戏。我通常从一个接近目标平台的defconfig开始然后逐项调整。# 加载基础配置 make ARCHarm xxx_defconfig # 进入配置界面 make ARCHarm menuconfig在menuconfig里重点检查这几个位置Security options确认SELinux或AppArmor已启用审计子系统已启用。Kernel hacking关闭大部分调试选项只保留必要的。Device Drivers只保留实际用到的驱动去掉无关的。Networking support如果不需要网络整个网络栈都可以裁掉。配置完成后编译内核make ARCHarm CROSS_COMPILEarm-linux-gnueabihf- -j$(nproc) zImage dtbs编译出来的zImage是内核镜像dtbs是设备树。这两个文件后面要打包到启动镜像里。4.3 根文件系统的构建与加固根文件系统我一般用Buildroot来构建因为它可以精确控制包含哪些包。配置Buildroot时重点是只选必要的包不要图省事全选。启用rootfs的完整性保护比如dm-verity。配置文件权限敏感文件只允许root访问。# Buildroot配置 make menuconfig # 关键配置项 # Target packages - 只选必要的 # System configuration - 设置root密码、启用登录限制 # Filesystem images - 启用dm-verity构建完成后会生成一个根文件系统镜像。这个镜像在烧录前要签名启动时由内核验证签名。4.4 启动验证与审计日志的联调所有组件准备好之后最后一步是联调。把U-Boot、内核、设备树、根文件系统打包成启动镜像烧到板子上然后验证启动过程中签名验证是否生效——可以故意改一个字节看是否启动失败。SELinux或AppArmor是否在强制模式——用getenforce查看。审计日志是否正常记录——执行几个关键操作用ausearch查看。不需要的服务是否已关闭——用systemctl list-units或ps检查。这一步最容易出问题的是签名验证。如果启动失败先看串口输出通常会提示哪一级验证没通过。常见原因是公钥没烧对或者签名时用的密钥和烧录的公钥不匹配。5. 踩过的坑和排查经验做合规嵌入式这些年踩过的坑不少这里挑几个典型的分享出来希望能帮后来人省点时间。5.1 常见问题速查表问题现象可能原因排查方法解决方式启动卡在U-Boot签名验证失败看串口输出检查公钥和签名是否匹配SELinux导致服务起不来策略过严ausearch看拒绝记录调整策略或先切宽容模式审计日志不记录auditd没启动systemctl status auditd启动服务并设置开机自启根文件系统验证失败dm-verity配置错误dmesg看内核日志检查哈希树和签名网络服务无法访问防火墙规则过严iptables -L查看规则按需放行端口5.2 几个容易忽略的细节第一个细节是时间同步。审计日志需要准确的时间戳如果设备时间不对日志的可信度就打折扣。嵌入式设备通常没有RTC电池开机时间可能从1970年开始。我的做法是启动时通过NTP同步如果网络不可用至少要从一个可信源获取时间。第二个细节是日志的存储位置。如果日志存在可写的文件系统上攻击者入侵后可以删改日志。合规要求高的设备日志应该实时发送到外部系统或者存在只追加的分区上。我一般会配置auditd把日志同时写到本地和远程syslog服务器。第三个细节是默认账号和密码。很多嵌入式系统出厂时带着默认的root密码这是合规审查的大忌。正确的做法是首次启动时强制修改密码或者每台设备用不同的随机密码。我见过一个产品因为所有设备用同一个默认密码被通报整改起来非常麻烦。5.3 合规不是一次性的是持续的过程最后想说一个观念上的问题。很多团队把合规当成一个过审的任务审过了就放松了。但实际上合规是一个持续的过程。系统要定期更新补丁、策略要随业务调整、日志要定期审查。我的建议是把合规检查集成到CI/CD流程里。每次构建固件时自动检查安全配置是否符合基线不符合就构建失败。这样从流程上保证合规状态不会因为人为疏忽而退化。# 示例构建后检查SELinux状态 if [ $(getenforce) ! Enforcing ]; then echo ERROR: SELinux is not in enforcing mode exit 1 fi上面这个检查脚本很简单但很有效。把它加到构建流程里就能防止有人不小心把SELinux关掉。嵌入式合规这件事说难也难说简单也简单。难的是要改变先功能后安全的开发习惯简单的是只要选对操作系统底座很多能力都是现成的。我在实际项目中的体会是越早把合规纳入设计后期返工越少。等到产品快量产了才想起来合规那改起来就是伤筋动骨。所以如果你正在做嵌入式项目不妨从选型阶段就把合规能力考虑进去后面会省很多事。
返回列表