3. GRUB2 引导校验:配置文件、密码保护与签名验证
GRUB2 这东西,说白了就是操作系统启动前的“守门员”。你想想看,如果这个守门员自己都不靠谱,那后面再怎么加固都是白搭。我在做安全审计时见过太多案例——内核打了全补丁,但 GRUB 配置被人改了,启动参数里加了个 init=/bin/sh,直接拿到 root shell。嗯,这章我们就来把 GRUB2 的防护做扎实。
3.1 GRUB2 配置文件结构
GRUB2 的配置文件不像老版 GRUB 那么单一。它的核心配置文件是 /boot/grub/grub.cfg,但注意——这个文件是自动生成的,你千万别直接手改它。我刚开始接触时也犯过这错,改完一执行 update-grub,全被覆盖了。
真正的配置入口在 /etc/default/grub,以及 /etc/grub.d/ 目录下的脚本片段。结构大概是这样的:
/boot/grub/grub.cfg # 最终生成的配置文件(不要手动编辑)
/etc/default/grub # 主配置入口
/etc/grub.d/ # 配置片段目录
├── 00_header # 基础设置
├── 05_debian_theme # 主题设置
├── 10_linux # Linux 内核启动项
├── 20_linux_xen # Xen 虚拟化支持
├── 30_os-prober # 其他操作系统探测
├── 40_custom # 自定义启动项
└── 41_custom # 另一个自定义入口
我个人习惯把自定义的密码保护和签名验证配置放在 40_custom 里,这样既不会被 update-grub 冲掉,也方便维护。
核心原则: 永远在 /etc/grub.d/ 里改配置,改完执行 update-grub 重新生成 grub.cfg。直接改 grub.cfg 等于白干。
3.2 GRUB2 密码保护
GRUB2 的密码保护分两种:一种是普通用户密码,一种是管理员(superuser)密码。区别在于——普通用户只能启动预设的菜单项,而管理员可以编辑启动参数、进入命令行、甚至绕过某些限制。
| 用户类型 | 权限范围 | 适用场景 |
|---|---|---|
| superuser | 编辑启动项、进入 GRUB 命令行、修改配置 | 系统管理员、安全审计 |
| 普通用户 | 仅能选择并启动预设菜单项 | 日常运维、普通用户 |
设置密码的步骤其实不复杂。首先用 grub-mkpasswd-pbkdf2 生成加密密码:
grub-mkpasswd-pbkdf2
# 输入密码后,会输出类似这样的哈希:
grub.pbkdf2.sha512.10000.ABCDEF...123456
然后把这段哈希写到 /etc/grub.d/40_custom 里:
set superusers="admin"
password_pbkdf2 admin grub.pbkdf2.sha512.10000.ABCDEF...123456
# 限制特定菜单项需要认证
menuentry "Production Kernel (restricted)" --unrestricted {
# 这个菜单项不需要密码
}
menuentry "Recovery Mode" --users admin {
# 只有 admin 能进恢复模式
}
最后执行 update-grub 生效。这里有个坑——我曾经遇到过 --unrestricted 参数没生效的情况,后来发现是 GRUB 版本太老。2.02 以下的版本不支持这个参数,得用 --users "" 代替。
注意: 密码保护只防住 GRUB 菜单界面的操作。如果攻击者能物理接触机器,用 Live CD 启动后直接挂载 /boot 分区,还是能改你的 grub.cfg。所以密码保护必须配合签名验证和 UEFI Secure Boot 一起用。
3.3 GRUB2 签名验证
密码保护防的是“操作”,签名验证防的是“篡改”。你想想看,就算设了密码,如果攻击者把 grub.cfg 里的内核路径改成他自己的恶意内核,那密码也拦不住——因为启动时加载的是被篡改过的配置。
GRUB2 的签名验证机制,说白了就是让 GRUB 在加载任何文件之前,先检查它的数字签名。只有签名合法的文件才被加载。
3.3.1 生成 GPG 密钥对
第一步,得有一套 GPG 密钥。我习惯用 RSA 4096 位,虽然慢一点,但安全冗余高:
gpg --gen-key
# 选择 RSA and RSA, 4096 位
# 填写姓名和邮箱,建议用组织统一的签名密钥
3.3.2 导出公钥并嵌入 GRUB
把公钥导出,然后嵌入到 GRUB 的 core image 里:
gpg --export > /boot/grub/pubkey.gpg
grub-install --pubkey /boot/grub/pubkey.gpg
这一步很关键——公钥是直接编译进 GRUB 引导镜像的。就算攻击者改了 /boot 分区里的文件,只要 core image 里的公钥没被换掉,签名验证就能生效。
3.3.3 对关键文件签名
需要签名的文件包括内核、initramfs、以及 GRUB 配置文件本身:
# 对内核签名
gpg --detach-sign /boot/vmlinuz-5.10.0
# 对 initramfs 签名
gpg --detach-sign /boot/initrd.img-5.10.0
# 对 grub.cfg 签名
gpg --detach-sign /boot/grub/grub.cfg
签名后会生成 .sig 文件,GRUB 在加载对应文件时会自动查找同名的 .sig 文件进行验证。
3.3.4 配置 GRUB 启用签名验证
在 /etc/default/grub 里加上:
GRUB_ENABLE_CRYPTODISK=y
GRUB_VERIFY_SIGNATURE=y
然后重新生成配置:
update-grub
避坑指南: 我曾经在升级内核后忘了重新签名,结果重启时 GRUB 报 "bad signature" 错误,直接进不了系统。后来我写了个脚本,在每次内核更新后自动执行签名操作,再也没出过这问题。
3.4 知识体系总览
下面这张图把 GRUB2 引导校验的完整链路串起来了。你可以看到,从配置文件生成到密码保护,再到签名验证,每一层都在解决不同的问题:
3.5 实战建议
讲完理论,说点实际的。我在生产环境里总结了几条经验:
- 密码和签名要一起上——单用密码,配置文件被换掉就废了;单用签名,攻击者拿到物理访问权后可以改配置绕过签名检查(因为签名检查只针对特定文件列表)。
- 密钥管理要规范——签名用的 GPG 私钥建议放在离线存储里,别放在服务器上。我见过有人把私钥和公钥放同一个目录,那签名还有什么意义?
- 定期轮换密钥——每年换一次签名密钥,旧密钥只用来验证历史文件,新密钥用来签名新文件。
- 测试环境先验证——别在生产环境直接改 GRUB 配置。先在测试机上跑一遍,确认密码能拦住、签名能通过、重启能正常进系统,再推生产。
一句话总结: GRUB2 的防护不是选做题,是必答题。密码保护 + 签名验证 + 合理的密钥管理,这三样缺一不可。