恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
嵌入式Linux安全加固实战:裁剪、权限、日志与防火墙
首页
资讯中心
/
嵌入式Linux安全加固实战:裁剪、权限、日志与防火墙
嵌入式Linux安全加固实战:裁剪、权限、日志与防火墙
发布时间:2026/9/8 7:36:26
三年前我接手过一批已经批量部署的路侧停车终端。固件是从上一代产品直接拷贝的root 密码还是出厂默认的 rootdropbear 停在 0.52内核里挂着 nfsd 和一堆用不到的 USB gadget 驱动。上线一个月运维就发现设备的 SSH 爆破日志刷了上百页——那一刻我才意识到嵌入式 Linux 的安全问题不是“以后再说”的小概率事件而是出厂默认配置直接送给攻击者的靶场。这篇是我主笔的嵌入式 Linux 实战专栏连载第 17 讲围绕系统级安全加固的四个核心动作展开最小化裁剪、权限硬化、日志审计、轻量防火墙。每一块我都会给出可落地的操作思路、配置参考和避坑经验并最后补上第 16 篇思考题的完整解析。适合正在做量产设备、或者刚把嵌入式 Linux 跑起来想往产品化方向走的工程师阅读。1. 开始前的威胁画像设备为什么总被盯上做加固之前先得搞清楚对手和攻击面。嵌入式设备跟云服务器不一样云服务器有专门的防火墙、入侵检测、补丁流程而嵌入式设备长期暴露在物理环境里固件更新周期长硬件资源又紧张跑不起复杂的检测代理。所以攻击者眼里这类设备就像“挂着钥匙的房门”。很多刚接触嵌入式 Linux 的工程师有个误区觉得只要功能正常、不崩不卡就算合格了安全是服务器才需要考虑的事。但实际做几个量产项目之后你就会发现安全设计必须在一开始就进架构等设备铺出去再补代价至少翻十倍。1.1 被低估的默认口令和老版本组件先看两个最常见的入口。第一是弱口令。很多量产固件出厂时保留 root/root、admin/admin 这类默认账号有的甚至直接在代码里写死不提供修改入口。设备一旦接入公网或专网扫描工具会按字典批量尝试常见密码。不要觉得“我的设备装在专网外网扫不到”专网里的横向移动本身就是攻击链条里很常见的一环你没法保证同一网段里其他设备都是干净的。我之前在排查一台被攻破的采集终端时发现攻击者根本不是从外网进来的而是先打穿了同一大楼里另一家公司的摄像头然后拿那台摄像头当跳板扫到了我这台设备的 SSH 端口。默认口令在这种攻击链里几乎就是一马平川。第二是长期不更新的老组件。做过交叉编译的都知道编译器、库、工具链往往在项目初期定版后就很少动了。于是 busybox 停留在老版本、openssl 残留多个已公开漏洞、dropbear 没打补丁——这些组件任何一个被利用攻击者就拿到了立足点。我见过最典型的情况开发阶段为了方便把 telnetd 编进固件发布时忘了关又因为根文件系统是完整拷贝的里面还留着 gcc、头文件和一堆示例代码。这等于把整套开发工具也送出去了。更麻烦的是这种问题往往在漏洞扫描工具面前藏不住一次合规检查就能把整个项目拖下水。经验把“组件版本台账”和“默认口令清单”列成交付物和原理图、BOM 一起归档。这块看起来是文档工作实际上决定了漏洞爆发时你能不能快速定位、能不能在客户质问之前给出答复。1.2 调试接口与供应链残留看不见的攻击面物理攻击也是必须考虑的维度。设备外壳上的调试串口如果直接暴露攻击者用 TTL 转 USB 线就能进入 bootloader 或系统 shellJTAG/SWD 接口更是可以直接接管 CPU。很多开发板默认把调试串口印在 PCB 上量产时也没做处理等于把后门焊在了板子上。有人会说“攻击者得有物理接触才能利用”但在无人值守的路侧设备、门禁闸机、充电桩这类场景里物理接触几乎是随时可能的。供应链残留则是另一类隐蔽问题。厂商提供的 SDK 里往往带着全套开发包NFS 启动支持、测试脚本、性能调优工具、远程调试服务。这些在开发期很顺手但一旦进了量产固件就成了攻击面的放大器。举个实际例子某设备为了让产线校准方便在镜像里保留了 adb 类似的远程调试服务结果被扫描到后直接成了攻击跳板。所以我们做加固时第一步不是去配防火墙而是先盘点固件里到底有什么。没有镜像清单后面所有加固动作都是盲打。攻击入口典型利用方式需要重点做的加固动作默认口令/弱口令字典爆破、横向移动登录随机化默认密码强制首次改密老版本组件漏洞利用 busybox/openssl/dropbear 漏洞版本台账 定期更新裁剪无用组件调试串口/JTAG进入 bootloader 或 shell物理屏蔽bootloader 加密认证供应链残留服务telnetd/调试服务被扫描发布前做镜像清单审计未加固的网络服务非法访问 Web/SSH 端口轻量防火墙 最小权限账号这个表格基本对应了后文四个加固动作。接下来从最“釜底抽薪”的一步讲起最小化裁剪。2. 最小化裁剪把攻击面从“干净”缩到“可数”最小化裁剪的本质不是把系统改得越小越有成就感而是删掉一切业务不需要的代码路径。一个功能模块没被编译进内核攻击者就根本没办法调用它一段代码不存在于文件系统里漏洞就无从谈起。这是成本最低、效果最稳定的安全手段。很多人以为裁剪是为了省 Flash 空间节省空间只是一个副产品真正的核心价值是收缩攻击面。2.1 内核裁剪的思路与步骤以功能清单反推配置很多工程师裁剪内核时是“开着 menuconfig 勾选项凭感觉删”。我的建议是反过来先整理产品的功能清单再把每个功能对应到内核配置项、设备树节点和用户态服务最后一条条映射成裁剪清单。功能清单要写到什么颗粒度拿一个路侧终端举例至少要有网口、4G 模块、GPS、串口屏、IO 采集、看门狗、日志存储、远程升级。每一项对应哪些驱动和配置要一清二楚。具体操作上可以先用make localmodconfig生成一个基于当前使用模块的最小配置再按需求手工微调。注意 localmodconfig 只在当前内核已加载模块的基础上收敛对新设备树里还没实际驱动到的硬件会误删所以跑完必须逐个核对启动日志和外设清单。内核裁剪不是一次性的工作每次硬件改版都要重新过一遍。生产环境建议关闭的内核选项我给一份参考清单CONFIG_DEBUG_FS调试文件系统线上环境关掉CONFIG_KALLSYMS内核符号表影响地址泄露和调试辅助CONFIG_IKCONFIG内核配置文件导出尽量关闭CONFIG_NFS_FS除非产品依赖NFS 客户端/服务端都不需要CONFIG_DEVMEM/CONFIG_DEVKMEM物理内存访问必须关未使用的网络协议如CONFIG_INET6若不用 IPv6、CONFIG_NETFILTER某些子模块同时保留这些基础项CONFIG_DEVTMPFS、CONFIG_TMPFS、CONFIG_SERIAL_CORE和串口驱动哪怕不留调试口早期启动日志也靠它以及文件系统对应的CONFIG_SQUASHFS/CONFIG_EROFS之类看你想用什么根文件系统。看着很简单但我在实际项目里踩过一个坑某主板启用 4G 模块后启动时 PPP 拨号一直失败排查半天发现是裁剪时把CONFIG_PPP相关的 PPP_ASYNC、PPP_SYNC_TTY 都删了。内核裁剪的坑大多不是“删坏了”而是“功能清单没覆盖全”。所以裁剪之后必须进入回归验证环节。2.2 根文件系统瘦身BusyBox、libc 与网络服务的取舍根文件系统是攻击者最喜欢栖身的地方。做瘦身时我一般按四层过。第一层是 libc。通用 glibc 功能全、兼容好但体积和依赖都重如果业务代码不需要 regex、iconv 等重度功能musl libc 是更轻的选择静态链接尤其省事。部分老驱动或闭源库可能对 glibc 有依赖换 musl 前先做 ABI 验证。我在一个项目里就把整个用户态换成了 musl镜像体积直接少了将近四成而且启动内存占用也降了。第二层是 BusyBox。BusyBox 本身是一个多功能集合编译时可以按需选择 applet。我用的是“最小 applet 列表”策略只保留产品启动、shell、基础文件操作、网络诊断需要的命令其余全关。测试时最方便的命令 top、hexdump、nc在量产固件里常常是不该出现的东西——它们同样方便攻击者。之前在某设备上见过一个攻击者先是用 nc 反向连出去下载了一个扫描工具然后就是一顿乱翻。如果固件里压根没有 nc这条攻击链就断了。第三层是网络服务。能不开就不开SSH 只有在远程维护确实需要时才放 dropbear并且用密钥登录HTTP 管理页面如果走局域网必须配访问控制和 HTTPSNTP、DNS 客户端按业务需要保留。记住一条原则默认不启动任何监听端口。你可以用netstat -lntup或 ss 检查一下系统当前到底有哪些端口在监听凡是清单外的全部关掉。第四层是开发期杂物。编译器、头文件、静态库、测试脚本、示例工程、符号文件统统不进镜像。一个常见做法是用 find 在打包前扫描并删除*.o、*.a、*.map这类文件。上层应用如果跑的是 AWTK 这类嵌入式 GUI 框架还要把资源文件和字体裁剪到最小集避免把整个 UI 示例工程塞进量产镜像。提示我现在维护的产物清单会精确到“每个文件的来源和用途”发布脚本里对这个清单做 diff凡是清单外的新增路径直接报错。这比靠人来审有效得多。2.3 裁剪后的回归验证不能只验证“能不能开机”裁剪之后最怕的是“开机没问题业务跑起来才发现少了东西”。我的回归清单大致包括启动时间裁剪前后对比确认没有因驱动缺失导致等待超时内存占用free、/proc/meminfo对比确认保留内存未被误裁剪外设清单网口、串口、USB、SD/eMMC、摄像头、音频逐项操作一遍存储介质性能如果是 SD 卡或 U 盘方案裁剪后最好做一轮读写测速排除因 DMA 配置、块设备驱动精简导致的性能骤降业务主流程跑一遍完整的产品业务比如数据上报、远程升级、日志回传如果团队有自动化测试条件把上述内容做成 smoke test 脚本每次镜像变更后自动执行。没有条件的至少出一份手动验证 checklist跟着走一遍。裁剪后的验证不能只看“能不能开机”必须看“所有业务功能是否与裁剪前一致”。一款设备如果只是能开机但数据上报异常、远程升级失败这种裁剪对生产来说是不可接受的。3. 权限硬化拒绝一把 root 梭哈到底嵌入式设备上最常见的安全陋习是所有进程都是 root 跑的文件和目录权限一律 777SSH 也允许 root 直接登录。系统里只有一个用户所有代码都是最高权限这就意味着任何代码漏洞都能直接拿到整机控制权。权限硬化的目标就是把“拿到一个进程”升级为“拿到整台设备”的门槛拉高。这个过程不复杂但需要打通账号、文件权限、能力位、挂载选项和内核参数好几个层面。3.1 账号体系重建从所有进程都是 root 到按需提权先做最简单的动作删除或禁用默认账号把 root 密码改成高强度随机值并禁止 root 的远程 SSH 登录。如果产品确实需要远程维护单独建一个维护账号shell 指定为受限命令集权限只覆盖维护脚本和日志读取。应用层更进一步建议用一个独立账号跑业务进程比如 app 用户数据目录和数据文件属主都明确授予不把 / 或 /etc 的写权限放给这个账号。日常操作如果需要临时提权可以配置 sudo 规则把可执行命令白名单化。之前有一个项目业务进程反复崩溃排查时发现是因为进程用 root 跑、日志路径又是随便写的后来我把它收紧为专用账号崩溃频率反而下来了——因为很多崩溃其实源于权限太宽、路径太乱导致的误写。我见过一个比较典型的分层设计分享给你参考角色账号权限边界用途系统管理员root仅本地 console禁止远程登录紧急运维远程维护maint仅能执行维护脚本和查看日志远程诊断业务进程app数据目录读写无系统管理权限运行主业务Web 服务www仅 web 目录读写网络端口绑定管理页面这套模型在普通 Linux 上很自然放到嵌入式上也完全适用区别只是资源更紧张需要更克制而已。3.2 文件、能力位和挂载选项的配合账号体系的下一层是文件权限和挂载选项。先说文件/etc/shadow、/etc/passwd文件权限要收紧/etc/ssh/ssh_host_*私钥文件必须 600应用配置里如果有密码或 token不要放在别人可读的路径下。关键目录的权限我常用的一组是chown root:root /etc /bin /sbin /usr chmod 755 /usr /bin /sbin /etc chmod 640 /etc/shadow chmod 600 /etc/ssh/ssh_host_rsa_key /etc/ssh/ssh_host_ecdsa_key能力位capabilities是另一个值得用的机制。嵌入式里最典型的需求是某个服务需要绑定 80 端口但不想给它 root。用 setcap 可以精确授权比如setcap cap_net_bind_serviceep /usr/bin/lighttpd这个操作看着简单实际项目里很实用。我之前做一个物联网网关Web 服务就是普通账号启动的但需要监听 80 端口解决方法就是绑定 8080 再在防火墙做转发或者直接给 cap_net_bind_service。用能力位可以省掉一次 NAT 转发也避免暴露额外端口更干净。再配合 sysctl 里的几个内核参数能够收敛内核级信息泄露sysctl -w kernel.kptr_restrict2 sysctl -w kernel.dmesg_restrict1 sysctl -w kernel.perf_event_paranoid3这些参数分别限制内核符号地址泄露、dmesg 访问权限和性能事件访问。嵌入式设备一旦被攻击者拿到低权限 shell这些信息就是它发起下一步攻击的重要基础堵掉它们成本极低收益却很明确。挂载选项也要动起来。根文件系统如果能做到只读就一劳永逸地解决了大量注入问题squashfs 或 EROFS 这类只读文件系统做根分区配合 overlayfs 或单独的可写数据分区既保留了运行期写数据的能力又不给攻击者篡改系统二进制文件的机会。可写分区挂载时尽量加noexec,nosuid,nodev选项这是成本极低的一层保险。你可以在/etc/fstab里这样配置/dev/mmcblk0p5 /data ext4 defaults,noexec,nosuid,nodev 0 03.3 阻断模块加载与调试后门内核模块加载接口一直是权限硬化的死角。攻击者拿到 shell 后很可能丢一个恶意 .ko 进来加载后直接读写任意内存。生产环境建议在机器启动早期执行echo 1 /proc/sys/kernel/modules_disabled echo 1 /proc/sys/kernel/modprobemodules_disabled 置 1 之后模块加载全部被禁止只能重启恢复。这个动作必须在系统启动脚本里尽早做而且要先确认所有驱动都已经被编译进内核不再需要动态加载。有些项目为了方便保留了一两个动态模块那就只能退而求其次用 module.sig_enforce 开启模块签名校验但总归没有直接禁掉干脆。调试后门也要同步关掉/proc/sys/kernel/core_pattern不要让崩溃程序把 core dump 写到任意目录/sys/kernel/debug、/proc/kcore如果不需要就不可访问Ptrace 范围收窄到当前用户避免调试器被滥用。最后强烈建议在 u-boot 里加密码保护bootdelay 设为 0限制串口交互命令避免攻击者从 bootloader 侧导入恶意环境变量。避坑提示modules_disabled 和 dmesg_restrict 这类项一定要在量产固件的启动脚本里做而不是依赖远程手工执行。手工配置很容易在整机重启后失效固件里固化才能真正落地。4. 日志审计留痕设计要解决“存哪、存多久、怎么防改”安全加固不全是“堵”还得有“看”。日志审计的价值在于当防线被突破时你能知道发生了什么、怎么发生的、影响范围有多大。这直接决定了事件响应速度。但在嵌入式设备上日志审计最大的约束是资源Flash 空间有限、内存紧张、CPU 也不宽裕不可能像服务器那样开全套审计方案。所以这一步的核心是按需取舍而不是贪多求全。4.1 哪些事件必须进日志不可能把所有事件都记录下来也没有必要。实际产品里我至少要求记录下面几类登录认证事件SSH 登录成功/失败、su 提权、Web 管理登录系统启动与重启每次冷启动、异常重启、看门狗复位服务状态变化关键进程启动、停止、崩溃重启网络事件网口插拔、IP 变更、防火墙规则变更配置变更关键配置文件被修改、固件升级、分区挂载变化硬件异常温度越限、电源电压异常、存储读写错误来源上busybox syslogd 或系统自带 syslogd 都能收集大部分应用层日志建议自行往独立的日志文件里写并附加时间戳。注意嵌入式设备经常没有 RTC 或电池刚启动时时间戳可能是乱的日志里必须依赖 NTP 同步后的时间否则审计时根本对不上时间线。我做调试时经常看到日志里时间戳从 2000 年 1 月 1 日跳变到当前时间如果设备没有 NTP 同步这部分日志是没法用的。4.2 存储选型与轮转策略日志存在哪儿是个需要权衡的问题。常见三种方案syslogd 直写 Flash实现简单但频繁写入会缩短 Flash 寿命且 Flash 写满后系统可能异常。日志写内存tmpfs速度快、不损耗 Flash但掉电即失无法追溯重启前的情况。日志写独立分区用 UBIFS 或 ext4 做独立日志分区配合轮转策略平衡寿命和持久性。我自己的默认方案是“内存缓冲 周期落盘”日志先写到内存里的环形缓冲区模块异常或定期把缓冲区同步到独立日志分区。这样既减少了 Flash 写入频率也保住了重启后的关键日志。再配合 logrotate 做轮转比如保留最近 4 份、每份 128KB基本能满足产品追溯需求。一个典型的 logrotate 配置片段取决于你用的具体版本和路径/var/log/messages { rotate 4 size 128k compress postrotate /usr/sbin/logger -t logrotate rotation done endscript }提示日志线程要考虑到“写日志导致系统变慢”的场景。数据上报高峰时日志写入如果抢占太多 I/O会让设备卡顿。我习惯给日志写入单独一个低优先级线程同时把 I/O 调度设成 noop 或 deadline减少对主业务的扰动。4.3 防篡改与远程汇聚的正确姿势日志如果不能防篡改审计就是空话。攻击者拿下设备后通常第一件事就是清理日志。我的经验是用两层第一层把所有日志文件的 owner 设为 root目录权限 700第二层把日志分区挂载为可写但仅 root 可进关键日志文件用chattr a加上 append-only 属性只能追加不能改写和删除。攻击者哪怕拿到业务账号也动不了历史日志。如果产品网络条件允许远程日志是更强的兜底syslog 客户端把关键日志推送到日志服务器即使设备被重启、日志分区被格式化远端记录还在。嵌入式设备资源有限远程日志注意两点一是只推审计类日志别把全部调试输出都推上来二是做好传输加密避免日志在网络上被截获。实际配置时busybox syslogd 的-R参数可以直接指定远程服务器地址简单场景完全够用但要注意网络抖动时本地日志别丢。5. 轻量防火墙低配主控如何守住网络边界最后一道网络边界防护是防火墙。嵌入式设备性能有限跑不了复杂的入侵检测系统但轻量防火墙完全可以在有限资源内完成“防非法访问、防横向扩散”的职责。很多开发者觉得嵌入式设备跑防火墙没必要因为业务端口就那么几个。但实际审计做过几轮之后就会发现防火墙规则是网络侧唯一的访问控制手段没有它所有端口都直接暴露给网络里任何一台机器。5.1 选型对照iptables 与 nftables 的嵌入式适配先解决选型问题。iptables 是经典方案资料多、团队熟悉但规则引擎老、语法底层是“表-链-规则”的堆栈式结构nftables 则是新一代框架规则集更紧凑、语法更清晰、Netfilter 上层的资源占用也更省。维度iptablesnftables内核要求2.4老内核通用3.13推荐 4.18规则集复杂度按表拆分维护成本高单个规则集文件链和规则表达清晰性能开销链条多时较高同类规则集更低团队熟悉度高需要短期学习成本体积二进制 库二进制 库略小如果内核版本较老比如 4.9 及以前或者团队长期维护 iptables 脚本继续用 iptables 完全没问题如果是新项目、内核 4.18 以上我更推荐 nftables。选型的核心是“团队能维护”而不是追新。我见过一个团队为了炫技在旧内核上强行移植 nftables最后因为工具链兼容问题浪费了两周。5.2 最小规则集设计与关键坑点无论用哪个规则集的设计思路一致默认拒绝按需放行。我做过一个路边终端的规则集业务只需要DHCP 获取 IP、DNS 解析、NTP 校时、向服务器主动上报数据、SSH 维护端口。防火墙规则如下nftables 示例table inet filter { chain input { type filter hook input priority 0; policy drop; ct state established,related accept iif lo accept udp dport 68 accept # DHCP udp dport 123 accept # NTP tcp dport 22 ip saddr 192.168.1.0/24 accept # 只允许维护网段 SSH tcp dport 2222 ip saddr 10.10.0.0/16 accept # 工厂维护端口 drop } chain output { type filter hook output priority 0; policy drop; ct state established,related accept iif lo accept udp dport 53 accept # DNS udp dport 123 accept # NTP tcp dport 443 accept # 上报服务器 udp dport 6881 accept # 数据通道按实际业务改 } }这里有个很容易踩的坑DHCP 客户端的报文源端口不定规则里直接放行目的端口 68 是常见做法但有些场景下 DHCP 是在 bridge 或特定网卡上跑的还要确认网卡名称和接口归属正确。NTP 同理要同时放行 UDP 123 且确认域名解析能走通。我遇到过一个案例工程师把 input 链的 policy 改成 drop 之后设备上不了网排查半天发现是 DHCP 的 udp 67/68 没放行设备压根拿不到 IP。另一个高频坑是 IPv6。很多裁剪掉 IPv6 的系统没问题但如果内核没关 IPv6outbound 到公网的流量可能走 IPv6而你的规则只写了 IPv4等于防护出现盲区。要么彻底禁用 IPv6要么把 IPv6 的 INPUT/OUTPUT 规则一并写好。最简单的做法是在 sysctl.conf 里设置net.ipv6.conf.all.disable_ipv61避免规则集出现盲区。5.3 性能实测百兆主控上的净滤开销很多工程师担心防火墙拖慢网速。以我实际测过的某 ARM 双核主控1.2GHz百兆网口为例纯转发场景下开启 conntrack 和少量规则吞吐量损耗大约在 1%-3%如果 CPU 很低频或者开了大量日志规则损耗可能到 5% 以上。所以在嵌入式设备上建议关闭 netfilter 的日志规则除非调试用并且不要对每个包都打印日志。conntrack 表也要设一个合理上限防止被大流量打满sysctl -w net.netfilter.nf_conntrack_max2048 sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established300经验上线前一定要用工具做一轮流量打点测试重点看 CPU 占用和内存变化。不要想当然嵌入式设备上同款芯片、不同网卡驱动的防火墙开销可能差一倍。6. 第 16 篇思考题完整解析文件系统与启动链路复盘上一讲第 16 讲的主题是嵌入式 Linux 文件系统与启动可靠性设计课后我留了 5 道思考题。这里把完整解析和判分点整理出来。没看过上一讲的同学也没关系答案本身会引到必要的背景。6.1 第一题量产环境下为什么没人直接用 ext4 做根文件系统题目为什么常见的开发板默认用 ext4/ext3 做根文件系统但量产消费类设备却往往不用解析开发板用 ext4 是因为方便支持动态读写、坏块处理相对透明、调试期随便挂载。但量产设备面对的是另一组约束eMMC/NAND 掉电场景下日志型文件系统元数据损坏的概率依然存在嵌入式设备掉电是常态不是异常ext4 对 NAND 原始设备支持不好必须搭配 FTL 层eMMC/SD 卡自带但裸 NAND 没有体积和只读需求很多量产方案希望根分区只读防止运行期被篡改ext4 的可写特性反而成了缺点启动时间只读镜像文件系统加载和挂载比 ext4 快资源开销也更低所以量产方案更常见的是squashfs/EROFS 做只读根分区搭配一个可写的数据分区ext4/UBIFS或者上 A/B 双分区做无缝升级。判分点能不能说出“根分区只读 独立可写分区”这个核心思路。6.2 第二题掉电损坏的根因与 A/B 分区方案题目设备在写入文件过程中突然掉电为什么文件系统会损坏A/B 分区方案为什么能缓解解析普通文件系统写入过程不是原子的。比如写一个文件先更新元数据inode、目录项再写数据块如果掉电发生在这两步之间元数据和数据就不一致轻则文件损坏重则目录结构错乱。日志文件系统ext4 的 journal、UBIFS能缓解一部分但不能完全避免。A/B 分区的核心不是“备份”而是“可回滚”。系统分为 A、B 两个槽位升级时只写非当前槽位写入完成并校验通过后切换启动项下次启动如果失败bootloader 自动回退到上一可用槽位。这样即使升级过程掉电导致某一侧损坏设备仍然能启动。这个思路和服务器上的双机热备有点像但实现成本低得多绝大多数嵌入式 SoC 的 bootloader 都支持。判分点是否答出“写入不原子 → 掉电损坏”的因果链以及 A/B 分区是“回滚机制而非备份机制”。6.3 第三题设备启动阶段最容易留下哪三类安全口子题目从 u-boot 到内核再到根文件系统挂载这条启动链路上安全口子通常在哪里解析这正是第 17 讲要堵的口子。三个高频问题u-boot 环境变量可被串口改写如果 u-boot 没设密码、bootdelay 不为 0攻击者按住回车就能进 u-boot改 bootargs 加init/bin/sh或者直接引导自制内核。应对设置 u-boot 密码、bootdelay0、启用校验。内核镜像和 dtb 未签名/未校验攻击者只要能替换 SPI Flash 里的内核镜像就能植入后门。应对启用 FIT image 签名或 Secure Boot如果芯片支持。根文件系统可写且 init 脚本不安全如果根分区可写攻击者可以改启动脚本持久化植入如果 init 脚本里把调试接口或远程执行打开了启动过程就成了后门。应对根分区只读启动脚本最小化关闭不需要的 console 服务。判分点三个层面都答到并且能说明每个口子的实际利用流程。很多人只答了 u-boot 密码忽略了内核签名和根文件系统只读这题只能拿一半分。6.4 第四题分区布局设计要考虑哪五个区域题目请为量产设备设计一个最小可用的 Flash 分区布局说明每个分区的作用和权限属性。解析一个典型的量产分区布局至少包含五个区域分区内容建议属性bootloader 区u-boot 或其他 bootloader 本体只读写保护环境变量区u-boot env 参数可写需校验和内核 dtb 区Linux 内核镜像和设备树只读建议签名根文件系统区squashfs/EROFS 只读根 fsA/B只读建议签名数据/日志分区业务数据、日志、升级包暂存可写权限收敛判分点有没有把 bootloader、内核、根文件系统、数据分区分开有没有对只读分区的写保护意识有没有把日志和升级包暂存规划进数据分区。6.5 第五题数据分区被迫可写时如何保护关键文件不被篡改题目如果产品必须使用可写的数据分区比如保存用户配置和日志你如何限制攻击者篡改关键文件解析这道题和第 17 讲的权限硬化关系最紧密。可行的思路包括文件权限和属主收敛关键配置文件属主 root、权限 640业务账号只有读权限挂载选项收紧数据分区挂载加noexec,nosuid,nodev关键日志追加保护对审计日志用chattr a防止被清空定期完整性校验对关键文件做 hash启动或运行时校验发现变更立即告警或恢复独立升级包校验远程升级包必须带签名升级前验签判分点能不能从“权限边界”“写入属性”“完整性校验”三个维度分别给出方案。只答 chmod 的说明思路还停留在入门阶段。6.6 课后点评这组思考题和第 17 讲加固动作的承接关系这组思考题表面上在考文件系统实际上是在给安全加固铺路。第一题和第二题让你决定根文件系统要不要做只读、要不要上 A/B 分区——这决定了整个权限模型的基座。第三题把视角带到启动链路——安全不是从 Linux 起来之后才开始的u-boot 阶段就已经决定了。第四题和第五题直接对应第 17 讲里的分区权限和文件权限硬化。所以学安全加固不能只看防火墙规则文件系统和启动链路里的每一个决定都在影响最终的安全水位。我遇到过不少工程师防火墙规则写得头头是道但根文件系统还是 ext4 可写、u-boot 还是裸奔状态这种加固在我看来等于只锁了房门没锁窗户。第 17 讲的内容到这里就完整了。按我自己的习惯每做完一次加固都会把“裁剪清单、权限矩阵、日志策略、防火墙规则”这四份产出单独存档并在下一次硬件改版时重新走一遍。嵌入式 Linux 的安全加固不是一个一次性动作而是一套和产品开发迭代同步的持续流程。如果在你的项目里也踩过类似的坑欢迎按同样的思路回查一遍固件——大部分问题光是把默认口令和多余端口清掉就能拦掉一大半低水平攻击。