了解如何设计和保护嵌入式Linux设备

2020-11-08 09:38:44

因为这个话题相当广泛,所以我分为两个部分。在第一部分中,我们将简单介绍安全概念和威胁建模,然后重点介绍一些提高嵌入式Linux设备安全性的缓解技术,包括安全引导、代码/数据加密和安全密钥存储。

如果您更喜欢一个小时的演讲而不是阅读本文,您还可以观看我为Toradex录制的网络研讨会“嵌入式Linux安全性简介”。我在2020年北美嵌入式Linux大会上也做了同样的演讲,但在我写这篇文章的时候,它还没有发表在YouTube上。

一方面,我们有所有者,那些从产品或服务中受益的人(用户、制造商、企业主等)。所有者想要保护资产,任何在产品或服务中有一定价值的东西(数据、代码、声誉等)。

另一方面,我们有威胁行为者,可以表现出威胁的人或物(恶意黑客、政府等),任何能够以可能导致伤害的方式对资产采取行动的东西。

要显示威胁,威胁行为者将通过攻击载体(威胁行为者用来访问或渗透目标系统的方法或路径)探索漏洞(系统中的弱点)。

归根结底,这是所有者和威胁行为者之间的猫捉老鼠游戏。业主会在多大程度上保护这些资产?威胁行为者会在多大程度上损害这些资产?这真的取决于资产的价值。事实上,所有者和威胁行为者对价值的看法可能不同。

识别资产(及其价值)以降低受到威胁的风险可以在一个称为威胁建模的过程中完成。

威胁建模是一个可以识别、列举潜在威胁并确定缓解措施的流程。这基本上是一个风险评估过程,在这个过程中,你要评估你的资产的价值和保护它们的成本。威胁建模的结果是产品的威胁模型。

有几种技术和方法可以在威胁建模期间提供帮助,包括大步、恐惧、广度、八度和许多其他方法。

为了对这个话题有一个非常基本的介绍,让我们来谈谈大步和恐惧。

STRIDE模型是帮助对威胁进行分类的非常有用的工具。它是由微软开发的,该名称是六种主要类型威胁的首字母缩写:欺骗、篡改、否认、信息泄露、拒绝服务和权限升级。STRIDE可用于识别系统资产可能面临的所有威胁。

DREAD方法是一种用于风险评估计算机安全威胁的工具。该名称是五类安全威胁的首字母缩写:损害(攻击有多严重)、可重复性(复制攻击有多容易)、可利用性(发动攻击的工作量有多大)、受影响的用户(有多少人会受到影响)和可发现性(发现威胁有多容易)。

STRIDE模型有助于识别威胁,而DREAD方法则有助于对它们进行排序。对于系统中的每个威胁,您可以查看每个威胁类别,并将其分类为低(1分)、中(2分)或高(3分)。最后,您将拥有一个威胁和缓解策略的排名列表。示例:

我们可以看到,威胁建模将提供一个非常清晰的视图,了解我们想要保护什么、我们计划如何保护它以及相关成本。这是产品威胁模型的一部分,每个开发周期都需要重新评估。因此,威胁模型将提供要处理的威胁的优先列表,这样我们就可以专注于实施缓解措施来提高产品的安全性。

如何保护代码的完整性和真实性?如何确保数据的私密性?在哪里存储加密密钥?如何将应用程序被利用的风险降至最低?让我们尝试回答所有这些问题以及更多问题,首先从安全引导开始!

如何确保您正在运行的代码是由值得信任的人或公司构建的?实施安全引导过程。

安全引导过程的目标是保护代码的完整性和真实性。

安全引导通常基于数字签名的验证。嵌入式Linux系统通常有三个主要组件:BootLoader、内核和根文件系统(Rootfs)。所有这些组件都已签名,并在引导期间检查签名。

例如,可以使用一些硬件机制来检查引导加载程序的签名,该引导加载程序将检查内核的签名,该引导加载程序将使用ramdisk镜像来检查根文件系统的签名。因为我们让一个组件检查引导链中下一个组件的签名,所以这个过程通常被称为信任链。

让我们来看看恩智浦iMX6设备上的一个真实例子。

一切都始于SoC内部的ROM代码。在恩智浦iMX6上,有一个名为高保证引导(HAB)的硬件组件,它能够验证第一阶段引导加载程序的签名,从而实现安全的引导过程。IMX6设备内的高保证引导也可以称为信任根,因为如果它受到威胁,所有安全引导过程也会受到威胁。

IMX6 SoC内部的ROM代码将使用HAB组件检查引导加载程序的签名。为此,需要生成一对密钥(公钥和私钥),用私钥对引导加载器签名,并将公钥存储在SoC中。在iMX6上,动态口令保险丝用于存储密钥。实际上,为了降低成本,SoC中只存储了公钥的散列。

当BootLoader启动时(例如U-Boot),它必须检查Linux内核的签名。为此,通常使用一种称为FIT IMAGE的图像格式。FIT镜像是具有散列和签名支持的多个二进制文件的容器,通常包含Linux内核镜像、设备树文件和初始ramdisk。在生成一对密钥之后,我们需要使用私钥e Configure U-Boot对FIT图像中的二进制文件进行签名,以使用公钥检查FIT图像的签名。

内核引导后,它将从ramdisk镜像运行init程序。Ramdisk将具有在挂载最终根文件系统之前验证其完整性的逻辑。有一些选项可以实现这一点。一种常见的选择是使用设备映射器验证(dm-verity)内核模块。Dm-verity内核模块提供块设备的完整性检查,并且需要只读的rootfs(squashfs可以是一个很好的解决方案)。如果需要读写根文件系统,其他方法可以是ima或dm-Integrity。

这只是安全引导实施的一个例子,尽管它可以应用于不同的主板和ARM SoC集合。

2017年7月17日,几款恩智浦设备(i.MX6、i.MX50、i.MX53、i.MX7、i.MX28和Vybrid系列)的ROM代码中的安全启动漏洞被公开披露。如果你的信任链受损,一切都会受损!因此,我们需要意识到这些类型的漏洞(在本例中,它们是用新的硅片修复的)。

虽然安全引导可确保真实性和完整性,但它不能防止设备被伪造或威胁攻击者从设备中提取代码/数据。因此,如果您想要保护您的知识产权或确保数据机密性,您将需要使用加密。

当您需要保护用户的隐私和机密性时,数据加密是一种常见的方法。数据是在设备执行期间生成的任何信息,包括数据库、配置文件等。

代码加密取决于具体情况,加密完整的根文件系统并不常见。通常,大多数组件都是免费的开源软件,所以没有什么好隐瞒的。还有GPLv3和Tivoization的问题(使用任何GPLv3软件都会迫使你为用户提供一种更新软件的机制,这将使你在加密软件时更加困难)。更常见的用例是只加密您为设备开发的应用程序。这通常是你的知识产权所在的地方。

在Linux中,基本上有两种主要的加密方法:全磁盘加密和基于文件的加密。

全磁盘加密提供块级别的加密,整个磁盘或磁盘分区被加密。为此,我们可以使用dm-crypt,这是Linux内核的设备映射器加密目标。

基于文件的加密在文件系统级别提供加密,其中每个目录可以单独使用不同的密钥进行加密,并且可以选择使用不同的密钥进行加密。基于文件的加密的两个最常见的实现是fsccrypt和eCryptFS。Fsccrypt是一些文件系统(如EXT4、UBIFS和F2F)上可用的API,而eCryptFS是一种更通用的解决方案,它是作为堆叠在现有文件系统之上的层实现的。

由于非对称密钥算法速度太慢,无法用于加密,因此通常使用对称密钥算法进行加密。这意味着加密和解密使用相同的密钥,该密钥应该在文件系统中的某个位置可用,以便可以解密加密的代码/数据。

但我们不能就这样把密钥留在文件系统里,对吗?

有几个案例表明,公司并不关心这一点,并为此付出了代价。例如,下面的图片来自第一台Xbox视频游戏机。安全研究员Andrew“Bunnie”Huang能够开发出一种专门的FPGA硬件来嗅探通信总线,并从设备中提取加密密钥。仅仅是因为密钥在那里,在通信总线上以明文传输,没有任何保护(顺便说一句,Andrew Huang是一本关于硬件黑客的非常好的书《黑客攻击Xbox》的作者,你可以在他的网站上免费下载)。

结论是,对加密的代码/数据的保护与对其解密的密钥的保护一样安全!

在台式机或智能手机上,用于加密文件系统的密钥可以从交互输入的用户密码(密码短语)中获得。例如,安卓智能手机就是这样运行的。

在嵌入式系统上,我们通常不需要用户交互来在每次引导设备时从密码派生密钥。因此,密钥应该加密存储在文件系统或安全存储中。为此,我们需要硬件支持。

例如,恩智浦i.MX处理器拥有唯一的主密钥(由恩智浦预先编程),只能由名为CAAM(加密加速器和保证模块)的特殊硬件模块访问。该硬件设备可用于加密密钥并将其存储在文件系统中(这必须在制造过程中完成)。在引导期间,CAMM模块将用于解密密钥并恢复将用于解密文件系统的明文密钥。由于CAAM模块内部的密钥不可访问,因此加密的密钥是受保护的。

如果处理器中没有可用的安全功能,则可以使用外部硬件(如安全元件或TPM设备)实现相同的结果。这些外部设备通常提供安全存储,因此它们可用于存储可用于加密/解密文件系统加密密钥的主密钥。这些设备还提供了许多安全功能,如随机数生成、散列计算、加密和签名功能等。

安全元件是安全计算系统。它基本上是带有自己的安全应用程序的安全存储(通常使用Java Card实现,但不是必需的)。安全元素的作用是非常开放的,并且取决于实现,但它们中的大多数都实现了公钥加密标准11(PKCS#11)。安全元件的例子是智能卡和SIM卡。

可信平台模块是一个规范和国际标准(国际标准化组织/国际电工委员会11889)。TPM不是一个安全元素,尽管它可以在其中实现。它可以在硬件或软件中实现,但大多数实现都在硬件中。它提供了该标准定义的一组有限的安全功能,包括安全存储和加密功能。

安全存储的第三种替代方案是使用可信执行环境(Trusted Execution Environment)。TEE是一种环境,在该环境中,执行的代码和访问的数据在机密性(没有人可以访问数据)和完整性(没有人可以更改代码及其行为)方面受到隔离和保护。我们周围的许多设备都使用可信执行环境,包括智能手机、机顶盒、视频游戏机和智能电视。如果您想了解TEE如何工作的更多细节,可以阅读我的文章“Trusted Execution Environment and ARM‘s TrustZone简介”。

最后,如果您关心嵌入式Linux设备中的加密,则必须从项目开始就考虑密钥存储和管理。

到目前为止,我们已经讨论了安全引导和加密来提高嵌入式Linux设备的安全性。但这还不够。我们应该始终考虑层次分明的安全性,每一层都应用一种建立在其他层之上的缓解技术,以提高设备的安全性。多种缓解技术的结合会让攻击者更难破坏设备。

想想看。您可以通过安全引导和加密来保护您的代码和数据,但如果您运行的应用程序有可能被利用的错误,您的资产仍然面临风险。如果应用程序具有攻击载体(用户输入、配置文件、网络通信等),则可利用漏洞来攻击该应用程序。特别是在使用内存不安全的语言(如C和C++)编写的程序中,缓冲区溢出等错误可用于堆栈崩溃和格式字符串等攻击。

因此,未来还会有更多的缓解技术出现。在本文的第二部分中,我们将介绍安全编码、静态分析工具、运行时保护、模糊工具、权限和功能、强制访问控制、应用程序沙箱等等!

关于作者:塞尔吉奥·普拉多(Sergio Prado)从事嵌入式系统工作已有20多年。如果你想了解更多关于他的作品,请访问关于页面或嵌入式Labworks网站。

请通过电子邮件将您的意见发送到Embeddedbits.org上的Sergio,或者订阅时事通讯以接收最新消息。