Zephyr 安全概述
简介
本文档概述了 Zephyr 安全子委员会为建立一套明确的安全流程所采取的步骤,该流程可帮助开发者构建更安全的软件,同时满足安全合规要求。文档阐述了安全流程的核心理念,并说明了需要创建哪些文档。在流程落地实施且所有配套文档创建完成后,本文档即为顶层概述和入口。
概述与范围
我们首先概述 Zephyr 的开发流程,其重点关注安全功能。
后续各节将详细讨论流程的各个组成部分。如图 1 所示,这些主要步骤包括:
安全开发: 定义系统架构和开发流程,确保遵循相关的编码原则和质量保证规程。
安全设计: 定义安全规程并实施强制执行的措施。创建系统及相关子模块的安全架构,识别威胁并设计对策。通过代码审查检查这些措施的正确实现以及威胁模型的有效性。最后,应定义用于报告、分类和缓解安全问题的流程。
安全认证: 定义 Zephyr RTOS 中可认证的部分,包括评估目标、其资产以及这些资产的保护方式。应确定认证声明,并以适当的证据作为支撑。
目标读者
本文档是 Zephyr 安全子委员会和 Zephyr 技术指导委员会制定安全流程的指南,为(安全)工程师和架构师提供 Zephyr 安全流程的概述。
术语约定
在本文档中,关键字 “MUST”、“MUST NOT”、“REQUIRED”、“SHALL”、“SHALL NOT”、“SHOULD”、“SHOULD NOT”、“RECOMMENDED”、“MAY” 和 “OPTIONAL” 应按照 [RFC2119] 中的描述进行解释。
这些词用于定义绝对要求(或禁止事项)、强烈建议的要求以及完全可选的要求。正如 RFC-2119 所指出的:“这些术语常用于规定具有安全影响的行为。未实现 MUST 或 SHOULD,或做了规范规定 MUST NOT 或 SHOULD NOT 做的事情,其对安全的影响可能非常微妙。文档作者应花时间详细阐述不遵循建议或要求所带来的安全影响,因为大多数实现者无法获得制定该规范时所积累的经验和讨论。”
安全文档更新
本文档是一份动态更新的文档。当发现新的需求、特性或变更时,将通过以下流程将其添加到本文档中:
相关方将通过向 Zephyr 文档仓库提交拉取请求的方式提交变更。
Zephyr 安全子委员会将审查这些变更,并给出反馈或接受变更。
变更一旦被接受,即成为本文档的一部分。
当前的安全定义
本节回顾 Zephyr RTOS 内安全开发的当前状况。目前重点关注功能安全和代码质量保证,同时也在规划其他安全特性。
目前实施的三大安全措施包括:
安全 功能,重点在于密码算法和协议。对密码硬件的支持已纳入未来版本的计划。Zephyr 运行时架构是单一二进制,无需动态加载器,从而减小了暴露的攻击面。
质量保证 通过采用要求所有代码在提交到公共仓库前必须经过审查的开发流程来实现。此外,重用网络协议栈等经过验证的构建模块可提高整体质量水平并保证 API 的稳定性。静态代码分析提供额外的质量检查。
执行保护 包括线程隔离、栈保护和内存保护,自 1.9.0 版(栈保护)起在上游 Zephyr RTOS 中提供。内存保护和线程隔离分别在 1.10.0 版(X86)和 1.11.0 版(ARM 和 ARC)中加入。
以下小节将更详细地讨论这些主题。
安全功能
Zephyr 中的安全功能主要取决于密码算法的引入及其单体系统设计。
密码功能通过 PSA Crypto 提供,底层实现为 Mbed TLS。应用程序利用 PSA Crypto API,确保以标准化且安全的方式进行密码操作。作为 PSA Crypto 的实现,Mbed TLS 支持广泛的密码算法,适合各种应用需求。
计划为硬件和软件形式的厂商专用密码 IP 提供 API,包括以安全访问模块(SAM)、可信平台模块(TPM)和可信执行环境(TEE)形式实现的安全密钥存储。
安全架构基于单体设计,Zephyr 内核和所有应用程序被编译为单个静态二进制文件。系统调用以函数调用的方式实现,无需上下文切换。静态链接消除了动态加载恶意代码的可能性。
后续版本还提供了更多保护特性。栈保护机制用于防止栈溢出。此外,应用程序可以利用线程隔离特性将系统划分为特权和非特权执行环境。内存保护特性支持对系统资源(内存、外设地址空间等)进行分区,并将资源分配给单个线程或线程组。栈、线程执行级别和内存保护约束在上下文切换时强制执行。
质量保证
Zephyr 项目采用自动化的质量保证流程。目标是建立一个包含强制代码审查、特性与问题管理/跟踪以及静态代码分析的流程。
代码审查通过投票系统进行记录并强制执行,之后由负责的子系统维护者将其检入仓库。代码审查的主要目标包括:
验证实现功能的正确性
提高所贡献源代码的可读性和可维护性
确保字符串函数和内存函数的使用得当
验证用户输入
审查安全相关代码中的潜在问题
当前的编码原则主要关注编码风格和约定。功能正确性由构建系统和审查者的经验来保证。特别是对于安全相关代码,需要制定具体而详细的指南,并与开发者达成一致(参见 安全代码)。
Zephyr 代码树会定期运行静态代码分析,参见 静态代码分析。
缺陷和问题的跟踪与管理通过 GitHub 进行。“可存续性”(survivability)一词用于涵盖安全问题分类和管理等主动安全任务。被认定为漏洞的问题通过 GitHub 安全公告进行管理。
由静态分析发现的问题在作为非问题关闭之前,应经过更严格的审查(关闭前至少需要另一位受过安全流程培训的人员同意该问题为非问题)。
已成立安全子委员会来更详细地制定安全流程;本文档是该流程的一部分。
执行保护
执行保护已得到支持,可分为以下任务:
内存隔离: 内存将被划分为多个区域,并根据内存区域的所有者分配属性。线程只能访问其控制的区域。
栈保护: 栈保护机制提供检测和捕获栈溢出的手段。各个线程应只能访问自己的栈。
线程隔离: 各个线程应只能访问自己的内存资源。线程被调度时,只有该线程拥有的内存资源可被访问。程序流保护以及其他防篡改措施目前不在讨论范围内。
系统级安全(生态系统等)
系统级安全涵盖多种类别,例如:
安全/可信启动
空中下载(OTA)更新
外部通信
设备认证
板载资源的访问控制
Flash 更新
安全存储
外设
信任根
减小攻击面
其中一些类别相互关联,需要多个部分协同到位才能为应用提供完整的解决方案。
安全开发流程
安全代码的开发应遵循特定准则,包括编码指南和开发流程,这些准则大致可分为软件质量和软件安全两类。此外,应创建系统架构文档,并随未来的开发保持更新。
系统架构
图 2 给出了 Zephyr 系统架构的高层示意图。该架构分为 OS 部分(内核 + OS 服务)和用户特定部分(应用服务)。OS 部分本身包含底层、平台特定的驱动,以及 I/O API、文件系统、内核特定功能和密码库的通用实现。
应创建一份描述系统架构和设计选择的文档,并随未来的开发保持更新。该文档应包含 Zephyr OS 的基础架构以及重要子模块的概述。对于每个模块,应创建专门的架构文档,并对照实现进行评估。这些文档应作为新开发者的入口和安全架构的基础。详细信息请参阅 Zephyr 子系统文档。
安全编码
设计像 Zephyr 这样的开放软件系统并使其安全,需要遵循一套明确的设计标准。这些标准包含在 Zephyr 项目文档中,特别是 安全代码 一节。在 [SALT75] 中,定义了以下被广泛接受的保护机制原则,用于防止安全违规并限制其影响:
开放设计 作为一项设计原则,其要义是:在任何广泛使用的系统上,保护机制都无法保密。应使用被公开认可的密码算法和成熟的密码库,而不是依赖保密的、定制的安全措施。
机制经济性 要求系统的基础设计应尽可能简单和小巧。在 Zephyr 项目中,这可以通过模块化代码 [PAUL09] 和抽象 API 等方式实现。
完全仲裁 要求对每个对象和进程的每次访问都必须先通过认证。应尽可能避免使用存储访问条件的机制。
故障安全默认值 要求默认情况下限制访问,仅在系统保护方案定义的特定条件下才允许访问,例如认证成功之后。此外,服务的默认设置应以提供最大安全性为原则来选择。这对应于 “默认安全”(Secure by Default)范式 [MS12]。
权限分离 是指授予访问权限之前需要满足两个或更多条件的原则。在 Zephyr 项目中,这可以包括拆分密钥 [PAUL09]。
最小权限 描述了一种访问模型,其中每个用户、程序和线程只应拥有执行其任务所需的最小系统权限子集。这种积极的安全模型旨在最小化系统的攻击面。
最小公共机制 要求多个用户或进程共用的机制在非严格需要时不应共享。[SALT75] 中给出的例子是:某个函数应实现为由每个用户执行的共享库,而不是由所有用户共享的超级用户过程。
心理可接受性 要求安全特性对开发者而言易于使用,以确保其被采用且应用正确。
除这些通用原则外,以下几点专门针对安全 RTOS 的开发:
互补安全/纵深防御: 不要依赖单一的威胁缓解方法。在互补安全方法中,部分威胁缓解由底层平台完成。如果平台未提供此类机制或这些机制不可信,则应采用纵深防御 [MS12] 范式。
默认关闭不常用的服务:为减少系统暴露于潜在攻击的机会,很少使用的特性或服务不应默认启用([MS12] 中给出的阈值为 80%)。对于 Zephyr 项目,这可以通过配置管理来实现。每项功能和模块都应表示为配置选项,并需要显式启用。这样,特定用例不需要的所有特性、协议和驱动都可以被禁用。如果启用了低层选项和 API 但应用未使用,则应通知用户。
变更管理: 为保证系统变更的可追溯性,每项变更都应遵循规定的流程,包括变更请求、影响分析、批准、实现和验证阶段。每个阶段都应提供相应的文档。所有提交都应关联问题跟踪器中的缺陷报告或变更请求。没有有效关联引用的提交应被拒绝。
基于这些设计原则和被普遍接受的最佳实践,应制定、发布安全开发指南并将其纳入 Zephyr 开发流程。更多细节请参见 安全设计 一节。
Quality Assurance
质量保证部分涵盖以下准则:
遵循编码规范 涉及编码风格以及模块、函数、变量等的命名方案。这可提高 Zephyr 代码库的可读性并便于代码审查。这些编码规范在检入之前由自动化脚本强制执行。
遵循部署指南 可确保发布保持一致,具有文档齐全的特性集和可跟踪的安全问题列表。
代码审查 确保代码库的功能正确性,并应在每次拟议的代码变更检入之前进行。代码审查应由至少一名独立于代码变更作者的审查者执行。这些审查由子系统维护者和开发者在功能层面进行,应与 安全设计 一节中所述的安全审查区分开来。更多信息请参阅 项目与治理 文档。
静态代码分析 工具能高效地检测大型代码库中的常见编码错误。所有代码在合并到主仓库之前都应使用适当的工具进行分析。这不是针对每次提交,而是按一定时间间隔在特定分支上运行。每次发布前必须移除所有发现的问题,或对潜在误报进行豁免。豁免应集中记录,并以注释形式记录在源代码中。文档应包含所使用的工具及其版本、分析日期、分支和父修订号、豁免原因、相应代码的作者以及豁免批准者。至少应在主发布分支和安全分支上运行。应确保每次发布在静态代码分析方面(包括豁免)都没有问题。更多信息请参阅 项目与治理 文档。
复杂度分析 应作为开发流程的一部分执行,并评估圈复杂度等指标。主要目标是使代码尽可能简单。
自动化: 审查流程和编码规则遵循情况的检查是预提交检查的强制部分。为确保一致执行,应将它们作为预提交过程的一部分实现自动化。在从子系统合入大量代码之前,除审查流程和编码规则遵循情况外,还必须已运行所有静态代码分析并解决问题。
发布与生命周期管理
生命周期管理包含以下几个方面:
设备管理 涵盖在设备部署现场更新 Zephyr 设备的操作系统和/或安全相关子系统的能力。
生命周期管理: 应定义系统阶段,并在系统状态图中记录各阶段之间的转换。出于安全考虑,这应包括在检测到攻击时锁定设备,以及在达到使用寿命终点时终止设备。
发布管理 描述了定义发布周期、编写发布文档以及维护已知漏洞和缓解措施记录的过程。特别是出于认证目的,需要确保发布的完整性,以便日后能轻松检测出篡改(例如插入后门等)。
权限管理与保密协议(NDA): 如果所选认证有此要求,则需要通过适当的权限管理(例如独立的源代码仓库)和相关方之间的保密协议来确保系统的机密性和完整性。对于多方共享的仓库,应采取措施确保没有恶意代码被检入。
应评估这些要点对 Zephyr 项目所采用开发流程的影响。
安全设计
为获得可认证的系统或产品,需要明确界定安全流程,并对其应用进行监控和推动。该流程包括安全相关模块在其各个阶段的开发以及对所报告安全问题的管理。此外,需要为当前已知和未来的攻击向量创建威胁模型,并调查和缓解其对系统的影响。详细信息请参阅 Zephyr 项目文档中描述的 安全代码。
软件安全流程包括:
遵循安全开发编码规范 是强制性的,以避免单个组件破坏系统安全并最小化单个模块的脆弱性。虽然这可以部分通过自动化测试实现,但在安全关键的模块中仍需人工检查对策等安全特性的实现是否正确。
安全审查 应由安全架构师在每次面向安全的发布准备阶段以及 Zephyr 项目中安全相关模块每次变更时执行。该过程包括验证已实施安全措施的有效性、检查是否符合全局安全策略和架构,以及在需要时为安全认证准备审计。
安全问题管理 涵盖对潜在系统漏洞的评估及其缓解,如 安全问题管理 所述。
这些准则和任务需要纳入安全软件的开发流程,并应尽可能实现自动化。在系统层面,对于 Zephyr 安全分支的每个安全相关模块,都应指定直接负责的安全架构师来指导安全开发流程。
安全架构
上述通用指南应辅以系统和模块层面的架构安全设计。高层考虑因素包括:
确定 安全与合规要求
功能安全,例如在适用时使用密码函数
针对已知攻击向量设计 对策
记录安全相关的 可审计事件
支持 可信平台模块(TPM) 和 可信执行环境(TEE)
支持对使用 Zephyr 的设备进行 现场 更新 的机制
任务调度器与隔离
安全架构的开发基于从整体系统架构的结构概览中得出的资产。在此基础上,各个步骤包括:
识别资产,例如用户数据、认证和加密密钥、密钥生成数据(来自 RNG)以及安全相关的状态信息。
识别针对资产的威胁,例如机密性破坏、用户数据被篡改等。
定义需求,涉及资产的安全和保护,例如对策或内存保护方案。
安全架构应与现有系统架构和实现保持一致,以确定潜在偏差并缓解现有弱点。集成到 Zephyr 项目安全分支中的新开发子模块应提供描述其安全架构的单独文档。此外,还应考虑并记录它们对系统级安全的影响。
安全漏洞报告
有关报告安全漏洞的信息,请参见 安全漏洞报告。
威胁建模与缓解
针对 Zephyr RTOS 的安全威胁建模是开发准确的安全架构以及大多数认证方案所必需的。该过程的第一步是定义系统要保护的资产。接下来对系统如何保护这些资产以及存在哪些针对它们的威胁进行建模。识别出威胁后,创建相应的威胁模型。该模型包含资产和系统漏洞,以及对这些漏洞潜在利用方式的描述。此外,还应评估对资产、资产所在模块以及整个系统的影响。然后在模块和系统安全架构中考虑该威胁模型,并定义适当的对策以缓解威胁或限制利用的影响。
简而言之,威胁建模过程可分为以下步骤(改编自 [OWASP]):
定义资产
应用分解并创建适当的数据流图(DFD)
使用 [STRIDE09] 和 [CVSS] 方法进行威胁识别和分类
确定对策和其他缓解方法
该过程应在模块设计阶段以及模块或系统架构重大变更之前执行。此外,每当发现新的漏洞或利用方式时,都应创建新模型或更新现有模型。在安全审查期间,应由负责的安全架构师评估威胁模型和缓解技术。
应根据这些威胁模型和缓解技术派生测试,以证明对策的有效性。这些测试应集成到持续集成工作流中,以确保安全性不会因回归而受损。
漏洞分析
为发现软件实现中的薄弱环节,应执行漏洞分析(VA)。特别值得关注的是对密码算法、关键 OS 任务和连接协议的调查研究。
在纯软件层面,这包括:
在特定硬件平台上对 RTOS 进行 渗透测试,即将相应的 Zephyr OS 配置和硬件作为一个系统进行测试。
应考虑 侧信道攻击 (时序不变性、功耗不变性等)。例如,需要确保密码算法和模块的 时序不变性 以减小攻击面。这既适用于软件实现,也适用于使用密码硬件的情况。
应对暴露的 API 和协议执行 模糊测试。
上面给出的列表主要用于说明目的。对于每个模块以及整个 Zephyr 系统(通常针对特定硬件平台),应创建并执行适当的 VA 计划。这些分析的结果应纳入安全问题管理流程,并应总结经验形成指南,纳入安全编码指南。
如有可能(例如模糊分析),这些测试应集成到持续集成流程中。
安全认证
创建 Zephyr RTOS 安全分支的目标之一是构建可认证的系统或其可认证的子模块。认证范围和方案尚待确定。然而,许多认证(如通用准则 Common Criteria [CCITSE12])都要求提供评估声明确实得到满足的证据,因此下面概述了一个通用的认证流程。根据认证方案和评估级别的最终选择,该流程还需要进一步细化。
通用认证流程
一般来说,获得认证或预认证(参见 [MICR16])的步骤包括:
定义 Zephyr RTOS 内需要保护的 资产。潜在对象包括密码密钥等机密信息、通信日志等用户数据,以及可能的供应商或制造商知识产权(IP)。
开发 威胁模型 和 安全架构,以保护资产免受系统漏洞利用的影响。由于完整的威胁模型涵盖包括硬件平台在内的整体产品,这可以通过拆分模型来实现:其中包含经过预认证的 Zephyr 安全分支,供应商可利用它来认证其基于 Zephyr 的产品。
制定 评估目标,其中包含关于待评估和认证资产安全性的 认证声明,以及关于运行条件的假设。
提供 证据 以证明声明得到满足,包括安全开发流程的一致文档记录等。
这些步骤在前面的章节中也部分涉及。与这些章节相比,认证流程只要求考虑需要纳入认证范围的组件。例如,安全架构考虑系统层面的资产,可能包含与认证无关的条目。
认证选项
就安全认证本身而言,可以采取以下选项:
将 Zephyr 作为纯软件系统进行抽象预认证: 此选项需要对底层硬件平台和运行在 Zephyr 之上的最终应用作出假设。如果硬件和应用满足这些假设,则更容易实现完整认证。此选项最为灵活,但给产品供应商带来的负担最大。
在不针对特定应用的情况下对特定硬件平台上的 Zephyr 进行认证: 此场景描述使能运行 Zephyr RTOS 的安全平台。硬件制造商在对应用作出明确假设的前提下认证该平台。如果满足这些假设,最终产品的认证工作量很小。
对实际产品进行认证: 在这种情况下,认证的是包含特定硬件、Zephyr RTOS 和应用在内的完整产品。
在这三种情况下,都需要确定认证方案(例如 FIPS 140-2 [NIST02] 或通用准则 [CCITSE12])、认证范围(主流 Zephyr、安全分支或特定模块)以及认证/保证级别。
对于部分认证(选项 1 和 2),认证需要对硬件和/或软件作出假设。这些假设可包括 [GHS10]:
硬件平台及其环境具有 适当的物理安全。
硬件平台本身及所有连接的设备具有 充分的存储和时间信道保护 (不涉及远程连接)。
设备上仅运行 可信/已保证的应用
设备及其软件栈由 经过适当培训且值得信任的人员 配置和操作,且无恶意意图。
这些假设应作为安全声明和评估目标文档的一部分。