这是我们关于 OTA 软件更新的 7 部分系列文章的第 3 篇。 在
中,我们向您介绍了能够远程交付软件更新的所有重要原因,在 中,我们介绍了软件更新系统危险的所有原因。 今天,我们将会探讨保护您的软件更新系统的方法,这些方法乍一看似乎是安全的,但实际上并非如此,每个示例都有现实世界中著名的故障。软件更新系统的组成部分
让我们从最简单的系统开始。 有一个设备,它知道它可能需要更新。 为简单起见,我们还假设,更新是以单个文件的形式进行,并且设备知道它所需文件的名称以及服务器的地址,我们称之为存储库,在这个里面设备能够找到需要的文件。然后设备可以访问存储库,请求文件,下载并以任何可行的方式安装它:
在设计软件更新系统时,我们需要解决的最基本问题是:设备如何确信它收到的更新是可信的? 这是一个非常重要的问题,在物联网中则显得尤其困难,在大多数情况下,我们希望自动完成更新或在用户同意的情况下进行。我们通常不想要设备的用户来判断推送给他的更新是否可信。
让我们看看我们可能会选择的一些常见方法,以及这些方法存在的问题。
选项 1:验证存储库,设置安全通道
攻击者可能具备的一项常见能力就是拦截流量或冒充存储库。因此,只要我们可以确保设备能够验证其正在与之通信的存储库是真实的(并且可以在整个“对话”中持续验证),那么它就可以安全地安装所找到的更新文件。 而且由于我们已经有了一个完善的方法来做到这一点(我们一直依赖 TLS),所以我们达成目的了。
因此,您可以使用证书链,一直追溯到某个受信任的根证书颁发机构,以验证服务器的身份,并使用 TLS 为接下来数据传输设置加密连接。这样问题解决了,因为只要我们与正确的服务器通信并且有加密连接,我们应该没问题,对吧?
不完全是。 有两大问题。 首先,TLS 可能不会被破坏,但 TLS 所依赖的信任体系并不完美。曾多次发现根证书颁发机构发布证书以允许中间人攻击。 例如,
和 的国家证书颁发机构都被发现签发了假冒 Google 域名的欺诈性证书。 表明,欺诈性 TLS 证书也可以在网络犯罪市场和暗网上随处购买。其次,存储库本身可能会受到入侵。由于存储库的密钥用于签署每个请求,因此需要将其保存在服务器上,而攻击者可以从中窃取它。即使服务器的密钥存储在硬件安全模块中并且无法被窃取,获取服务器访问权限的攻击者仍然可以在其控制期间对连接的每台设备安装恶意软件。这正是 2013 年
所发生的事情,使大部分互联网陷入恐慌。攻击者利用了 中的漏洞。幸运的是,当时攻击者并没有恶意,只是想引起 RubyGems 团队的注意,以便他们修补漏洞。但是,如果他们愿意,他们可以发布 Rails 等流行的恶意版本,并接管(或窃取密码)任何碰巧在 RubyGems 存储库遭到入侵期间构建的 Ruby on Rails 网站,这包括 Twitter、Airbnb 和 Hulu 等网站。选项 2:签署您的软件
因此,很明显我们不能仅仅依赖于验证存储库的身份。那我们是否可以在将软件更新放入存储库之前,就为其添加一个准许印? 每个客户端都可以验证它,这样即使存储库被入侵,我们的用户仍能够保持安全。理论上这也是一种使用基于
的 很容易做到且非常安全的方式。我们生成一个离线密钥,确保我们的客户端拥有公钥,并让我们的软件更新程序拒绝任何没有有效签名的程序。什么是离线密钥? 离线密钥是未保存在任何连接到 Internet 的计算机上的密钥。它可能是像 Yubikey 这样的硬件设备,也可能是密钥文件存储在 USB 存储设备上并被保存在某个地方,只在需要时才取出。您不能将离线密钥用于 TLS 之类的东西,因为每次建立连接时都需要使用这些密钥。但是您可以将离线密钥用于很少发生的加密任务,例如签署主要软件版本。
这是 Red Hat 和 Debian 等主要 Linux 发行版采用的基本方法。(多年来进行了各种改进,但基本方法保持不变。)当您安装操作系统时,它会提供有一个
其可以自我更新。这使得更新软件可以安全地分发到世界各地的存储库镜像,而存储库不需要任何密钥。