Ubuntu系统通过apt-get安装软件时,默认会对下载的软件包进行GPG签名验证,但这个验证机制并非在所有场景下都被强制执行。很多管理员发现,当源配置不当、密钥缺失或者被中间人攻击时,apt-get仍然可能静默安装未经验证的包。要真正实现"强制签名验证",你需要从三个层面入手:确保APT源配置了强制验证策略、安装并信任正确的GPG密钥、以及在apt配置文件中锁定验证行为。下面我会一步步把这些操作讲透。
一、为什么apt-get的签名验证不是默认强制的
很多人以为apt-get装软件时自动就会验证签名,实际上Ubuntu的APT包管理系统在设计上是"尽力验证"而非"强制拒绝"。具体来说,当你添加一个新的软件源时,如果该源没有对应的GPG公钥,apt-get会给你一个警告,但不会阻止你继续安装。在某些旧版本或者特定配置下,甚至连警告都不会出现。这意味着如果攻击者能够控制你的网络流量或者篡改软件源镜像,他们可以向你推送恶意软件包,而系统不会主动拦截。
这种"软验证"的设计初衷是为了用户体验——避免因为密钥问题导致大量合法软件无法安装。但从安全角度看,这是一个明显的漏洞。尤其在企业环境、服务器集群、以及对安全性要求极高的场景中,必须把验证从"可选"变成"强制"。
二、检查当前系统的签名验证状态
在动手配置之前,先看看你的系统现在是什么状态。打开终端,运行以下命令查看已安装的GPG密钥:
apt-key list
你会看到一串密钥列表,包括Ubuntu官方密钥和你手动添加的第三方源密钥。如果某个源没有对应的密钥,或者密钥已经过期,那就是风险点。
再检查你的源列表文件:
cat /etc/apt/sources.list ls /etc/apt/sources.list.d/
每个.list文件里的源条目,如果没有写明signed-by参数,就意味着该源的验证是松散的。这是你需要修复的第一步。
三、强制签名验证的核心配置方法
Ubuntu从20.04开始,官方推荐使用新的密钥管理方式,不再依赖apt-key命令。你需要把GPG密钥文件放到/etc/apt/keyrings/目录下,然后在源配置中用signed-by显式指定。这是实现强制验证的关键步骤。
第一步:获取源的GPG公钥。以Docker官方源为例:
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
第二步:编辑对应的源文件,添加signed-by参数。比如创建/etc/apt/sources.list.d/docker.list:
deb [signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable
注意这里的[signed-by=...]部分,它告诉APT:"这个源的包必须用指定的密钥验证,验证失败就拒绝安装。"这就是强制验证的语法核心。
第三步:更新并测试。运行:
sudo apt update
如果配置正确,你会看到类似"Get:1 https://download.docker.com ... InRelease"的信息,并且不会有任何关于未签名包的警告。如果有警告,说明配置还有问题,需要回头检查。
四、通过APT配置文件锁定验证行为
除了在源条目中指定signed-by,你还可以在全局APT配置中进一步加固。编辑/etc/apt/apt.conf.d/目录下的配置文件,或者直接创建一个新文件,比如99force-verify:
APT::Get::AllowUnauthenticated "false"; Acquire::AllowInsecureRepositories "false";
这两行配置的含义非常明确:第一行禁止安装任何未经认证的包,第二行禁止使用不安全的源(比如没有HTTPS的HTTP源)。加上这两行之后,即使有人在源文件里写了错误的配置,系统也会从全局层面拒绝不安全的操作。
需要注意的是,如果你的某些内网源确实没有签名(比如私有仓库),这两行配置会导致无法更新。这种情况下,你需要为特定源单独创建例外配置,而不是关闭全局策略。可以在/etc/apt/preferences.d/中针对特定源设置:
Package: * Pin: origin "your-internal-repo.local" Pin-Priority: 500
但更好的做法是给内网源也加上签名,而不是绕过验证。
五、密钥管理的最佳实践
强制验证的前提是你信任正确的密钥。密钥管理做不好,强制验证反而会导致系统无法正常工作。以下是几个硬核建议:
1. 定期更新密钥。第三方源的GPG密钥可能会轮换,你需要定期检查并更新。可以写一个cron脚本每月自动拉取并更新密钥文件。
2. 验证密钥指纹。不要 blindly 信任从网络下载的密钥,一定要到源的官方网站核对指纹。比如Ubuntu官方密钥的指纹可以在Ubuntu官网的安全页面找到。
3. 删除过期和无用密钥。运行apt-key list时,如果看到expired或者来源不明的密钥,果断删除:
sudo apt-key del KEY_ID
4. 使用密钥环目录管理。Ubuntu 22.04之后,apt-key命令已经被标记为deprecated。所有密钥应该存放在/etc/apt/keyrings/下,用文件名而非密钥ID来管理。这是官方推荐的新标准,也更安全。
六、常见问题与排错指南
在实施强制签名验证的过程中,你可能会遇到以下问题:
问题一:apt update报错"NO_PUBKEY"。这说明源的公钥不在你的密钥环中。解决方法是找到对应的公钥并导入到/etc/apt/keyrings/目录。
问题二:安装时报"The following signatures couldn't be verified"。这通常是因为密钥过期或者源的签名密钥已经更换。去源的官方渠道获取新密钥更新即可。
问题三:某些包安装失败但你确定源是安全的。这种情况可能是因为包的签名时间戳有问题,或者你的系统时钟不准。先用date命令检查系统时间,如果时间偏差大,用ntpdate同步后重试。
问题四:内网源无法使用。如果你的环境有不支持签名的私有源,不要全局关闭验证,而是为该源单独配置,或者给它加上自签名证书。
七、进阶:结合其他安全机制形成纵深防御
强制签名验证只是软件供应链安全的一环。要真正保障Ubuntu系统的安全,还需要配合其他措施:
1. 使用AppArmor或SELinux限制apt-get进程的权限,防止即使被利用也无法执行高权限操作。
2. 开启apt的日志审计,记录所有包安装行为。可以在/etc/apt/apt.conf.d/中配置:
DPkg::Pre-Install-Pkgs {"/usr/sbin/dpkg-pre-install-logger %u";};3. 定期用debsums工具校验已安装包的完整性:
sudo apt install debsums sudo debsums -c
4. 考虑使用Ubuntu Pro或者第三方工具如AIDE进行文件完整性监控,确保系统文件没有被篡改。
八、总结
Ubuntu的apt-get签名验证从来不是"开箱即用"的强制机制,它需要管理员主动配置才能真正发挥安全作用。核心操作就是三步:把GPG密钥放到/etc/apt/keyrings/、在源条目中写明signed-by参数、在全局配置中禁止未认证和不安全源。做好这三步,你的Ubuntu系统在软件安装层面就具备了相当强的防篡改能力。安全不是一个开关,而是一套持续维护的体系,密钥要更新、配置要检查、日志要审计,缺一不可。
