安全编码
传统上,基于微控制器的系统并不太重视安全性。由于难以访问,它们通常被认为是孤立的、与外界隔离的,且不易受到攻击。物联网改变了这一点。如今,运行在小型微控制器上的代码通常可以访问互联网,或至少可以访问其他设备(这些设备本身可能存在漏洞)。鉴于其部署数量庞大,不受控制的访问可能造成破坏性后果 [1]。
本文档描述在 Zephyr 项目中确保安全问题得到处理的要求和流程。所有提交的代码都应遵循这些原则。
本文档的大部分内容来自 [CIIBPB]。
简介与范围
本文档从安全角度介绍 Zephyr Project 的指南。其中的许多理念取自其他开源项目的工作。
我们首先概述与 Zephyr 相关的安全设计。接下来是 安全开发知识 一节,其中给出参与本项目的开发者需要具备的基本要求。本节会引用其他安全文档,而编写安全软件的完整细节超出了本文档的范围。本节还描述了主要开发者中至少一人应具备的漏洞知识。这些知识对于下文所述的审查流程是必要的。
接下来描述用于将变更合入 Zephyr 代码库的审查流程。之后是有关项目如何处理安全敏感问题的文档。
最后,本文档介绍如何对本文档进行变更。
Secure Coding
设计像 Zephyr 这样的开放软件系统并使其安全,需要遵循一套明确的设计标准。在 [SALT75] 中,定义了以下被广泛接受的保护机制原则,以帮助防止安全违规并限制其影响:
开放设计 作为设计准则,包含这样一条格言:在任何广泛使用的系统中,保护机制都不能依赖保密。应使用公开认可的密码算法和成熟的密码库,而不是依赖保密的、定制的安全措施。
机制经济性 规定系统的基础设计应尽可能简单和小巧。在 Zephyr 项目中,这可以通过模块化代码 [PAUL09] 和抽象 API 来实现。
完全仲裁 要求对每个对象和进程的每次访问都必须先经过身份验证。如有可能,应避免使用存储访问条件的机制。
失效安全默认值 规定访问默认受到限制,仅在系统保护方案定义的特定条件下才允许,例如成功通过身份验证之后。此外,服务的默认设置应以提供最大安全性为选择依据。这对应于 “Secure by Default” 范式 [MS12]。
权限分离 是指授予访问权限之前需要满足两个或更多条件的原则。在 Zephyr 项目中,这可以包括拆分密钥 [PAUL09]。
最小权限 描述了一种访问模型:每个用户、程序和线程在系统中只应拥有执行其任务所需的最小权限子集。这种积极安全模型旨在最小化系统的攻击面。
最小公共机制 规定,如果不严格要求,则不应共享多个用户或进程共用的机制。[SALT75] 中给出的示例是:某个函数应实现为由每个用户执行的共享库,而不是由所有用户共享的管理程序。
心理可接受性 要求安全特性易于开发者使用,以确保这些特性得到使用且应用方式正确。
除了这些通用原则外,以下要点专门针对安全 RTOS 的开发:
互补安全/纵深防御:不要依赖单一的威胁缓解方法。采用互补安全方法时,部分威胁缓解由底层平台执行。如果平台未提供此类机制,或这些机制不受信任,则应使用纵深防御 [MS12] 范式。
不常用服务默认关闭:为降低系统暴露于潜在攻击的风险,如果某些特性或服务很少使用,则不应默认启用;[MS12] 中给出的阈值为 80%。对于 Zephyr 项目,这可以通过配置管理来实现。每个功能和模块都应表示为配置选项,并且需要显式启用。然后,可以禁用特定用例不需要的所有特性、协议和驱动程序。如果启用了低层选项和 API 但应用程序未使用它们,则应通知用户。
变更管理:为保证系统变更的可追溯性,每项变更都应遵循规定的流程,包括变更请求、影响分析、批准、实现和验证阶段。在每个阶段,都应提供适当的文档。所有提交都应关联问题跟踪器中的缺陷报告或变更请求。没有有效引用的提交应被拒绝。
安全开发知识
安全设计者
Zephyr 项目必须至少有一位知道如何设计安全软件的主要开发者。
这要求理解以下设计原则,包括 [SALT75] 中的 8 条原则:
机制经济性(使设计尽可能简单和小巧,例如采用大幅简化)
失效安全默认值(访问决策应默认拒绝,项目安装应默认安全)
完全仲裁(每次可能受限的访问都必须检查权限且不可绕过)
开放设计(安全机制不应依赖攻击者不了解其设计,而应依赖更易于保护和更改的信息,例如密钥和密码)
权限分离(理想情况下,对重要对象的访问应取决于多个条件,这样攻破一个保护系统不会导致完全访问。例如,多因素身份验证(如同时要求密码和硬件令牌)比单因素身份验证更强)
最小权限(进程应以所需的最小权限运行)
最小公共机制(设计应尽量减少多个用户共用且所有用户都依赖的机制,例如临时文件目录)
心理可接受性(人机接口必须设计得易于使用——考虑 “最小惊奇” 原则会有所帮助)
有限攻击面(攻击者可尝试进入或提取数据的不同点的集合)
使用允许列表进行输入验证(输入在被接受之前通常应检查其是否有效;这种验证应使用允许列表(仅接受已知良好的值),而不是阻止列表(试图列出已知不良的值))。
漏洞知识
项目中的 “主要开发者” 是指熟悉项目代码库、能够自如地对其进行修改,并得到项目大多数其他参与者认可的人。主要开发者通常会在过去一年中做出多项贡献(通过代码、文档或回答问题)。如果开发者发起了项目(且离开项目不超过三年)、可以选择通过私有漏洞报告渠道(如果有)接收信息、能够代表项目接受提交,或负责项目软件的最终发布,那么通常会被视作主要开发者。如果只有一位开发者,则该开发者就是主要开发者。
主要开发者中至少有一人 必须 了解此类软件中会导致漏洞的常见错误类型,并至少掌握一种应对或缓解每种错误的方法。
示例(取决于软件类型)包括 SQL 注入、操作系统命令注入、经典缓冲区溢出、跨站脚本、缺少身份验证和缺少授权。常用列表可参见 CWE/SANS top 25 或 OWASP Top 10。
非营利组织 OpenSecurityTraining2 面向 C/C++ 开发者提供了一门免费课程,可在 OST2_1001 获取。该课程讲授如何预防、检测和缓解线性栈/堆缓冲区溢出、非线性越界写入、整数溢出以及其他整数问题。后续课程 OST2_1002 涵盖未初始化数据访问、竞态条件、释放后使用、类型混淆和信息泄露漏洞。
Zephyr 安全子委员会
应设立 “Zephyr 安全子委员会”,负责执行本指南、监督审查并改进这些指南。
该团队将根据 Zephyr 项目章程设立。
代码审查
Zephyr 项目应使用要求所有变更都必须经过的代码审查系统。每项变更都应由至少一位非变更作者的主要开发者审查。该开发者应根据其对安全的总体理解,判断此变更是否影响系统安全;如果影响,则应请具备漏洞知识的开发者或安全设计者一同审查代码。在安全问题得到解决之前,上述任何人员都有权阻止变更合并到主线代码中。
问题与缺陷跟踪
Zephyr 项目应有一个问题跟踪系统(例如 GitHub),用于记录和跟踪系统中发现的缺陷。
由于安全问题通常较为敏感,该问题跟踪系统应有一个字段用于标明安全问题。设置该字段后,问题应仅对 Zephyr 安全子委员会可见。此外,还应有一个字段,允许 Zephyr 安全子委员会添加对特定问题具有可见权限的其他用户。
这种禁运期(即限制可见性)只应持续固定时长,默认值由项目决定。然而,由于安全考量通常涉及 Zephyr 项目之外的方面,可能有必要延长禁运时间。所需时间应在问题中明确注明。
Zephyr 安全子委员会应至少每月审查一次问题列表。审查应重点关注跟踪修复进展、确定是否需要通知或让外部相关方参与,以及确定何时解除对问题的禁运。禁运 不应 通过自动化方式解除,但审查团队应避免不必要地延迟解除已解决问题的禁运。
对本文档的修改
对本文件的更改应由 Zephyr 安全子委员会审查,并经协商一致批准。