软件系统安全性

软件系统安全性（software system safety）也称为软件安全（Software safety），要确保用在生命攸关系统的软件，不会让系统产生危害。

许多不同领域的安全标准，会指导安全相关软件如何开发和如何测试。大部分会依软件应用的关键程度为软件分级，并针对不同等级的软件，说明在开发和验证过程需要用的技术和量测方式：

- 通用电子安全关键系统的软件：IEC 61508（标准中的第3部分）
- 车用软件：ISO 26262 （标准中的第6部分）
- 铁路软件：EN 50716
- 飞航软件：DO-178C
- 空中交通管理软件：DO-278A/ED-109A
- 医疗软件：IEC 62304
- 核电厂：IEC 60880

## 词语

系统安全是总体性的要求，目的是要将技术系统中的风险降到可接受的程度，以此实现安全性。根据功能安全标准IEC 61508，安全是“不会有无法接受的风险或伤害”。软件本身可以视为是单纯的资讯，本身不会造成伤害，因此有时会将“软件安全”一词改为“软件系统安全”（例如Joint Software Systems Safety Engineering Handbook和MIL-STD-882E就使用此一词语）。后者强调软件只会造成其技术系统的伤害（参考NASA Software Safety Guidebook, chapter 2.1.2），而其伤害会对系统周围有影响。

软件安全的目的是确保软件不会造成所在系统的危害，而且此事可以确认并且证明。这一般是用指定软件的“安全等级”，并且选择适当的开发程序以及证认程序来达到。

## 指定安全等级

创建安全相关软件时的第一步是依照其安全关键程度来分类。不同安全标准有各自的分类：像是DO-178C的软件等级A-E、IEC 61508的SIL（安全完整性等级，Safety Integrity Level）1-4、ISO 26262的ASIL（车用安全完整性等级、Automotive Safety Integrity Level）A-D。

一般会在系统层级指定安全等级，也会评估软件失效的最坏后果。例如，车用标准ISO 26262要求在整车等级进行危害分析与风险评估（Hazard Analysis and Risk Assessment，简称HARA），以此推导某一元件上软件的ASIL。

## 流程遵守与保证

在考虑软件的安全性时，需要依软件的安全关键程度，使用充足的开发流程以及验证流程，配合适当的方法或是技术。软件安全标准可能会建议一些方法或是技术，甚至强制使用特定方法或技术，视安全等级而定。

大部分的标准都会建议生命周期模型（像是EN 50716、IEC 61508的SIL 1-4会要求V模型），并且说明在软件开发的不同阶段需要进行的活动。例如，IEC 61508要求软件需要有充份的规格说明（可能用型式方法或是半型式方法）、软件设计需是模组化且可测试的、需使用有充份功能的程式语言、需进行文件化的程式码评审、需有多层级的测试，以达到充够的测试覆盖率。

对软件开发流程和验证流程的注重是源自于一个事实：软件品质（和安全）会高度的受到软件流程的影响，如IEC 25010所述的一样。IEC 25010提出流程会影响内在的软件品质属性（程式码品质），因此也会影响外在软件品质属性（像是功能性和可靠度）。

以下是一些安全软件的开发流程中会提到的活动和概念。

### 文件

在本质上，所有软件安全标准都会要求针对开发流程和验证流程全面且完整的文件。通常这些文件需经过第三方的评审和核可，是安全相关软件核可的前提。文件包括许多的计划文件、需求规格、软件架构以及设计文件、不同抽象程度的测试案例、工具鉴定报告、评审证据、验证和确认（verification and validation）结果等。在EN 50716的图C.2中列出在开发生命周期中需要创建的32份文件。

### 可追踪性

需求可追踪性（Requirements traceability）是建立不同种类的需求之间的关系，需求和设计、实现和测试文件之间关系的实务。依照EN 50716，其目的是“确保所有需求都已妥善满足，没有引入任何无法追踪的东西”。透过建立可追踪性的文件，并且维护，就可能让一个安全需求对应到系统设计（以验证设计时已有充份的考量）、再对应到软件程式码（以验证程式码符合需求）、以及适当的测试案例以及测试实做（验证安全需求已被充份的测试）。

### 软件实现

安全标准中有些要求会直接影响软件程式码的实现，例如使用适当的程式语言、函式的大小和复杂度、使用特定的程式架构以及程式码标准等。在IEC 61508的第三章包括了以下的要求和建议：

- 使用强型态的程式语言。有些语言比较适合用在安全相关系统中。支援强型态的程式语言可以在编译时就侦测到错误，而不是在运行时才发现。因此，不建议用组合语言，建议使用针对安全相关市场的高阶语言（例如ADA）。
- 使用定义了“安全”语言子集的程式码标准，例如MISRA C。MISRA-C是C语言的程式码标准，为了是要提升程式码品质和安全性，此标准会不允许一些易错的程式写法、一些与编译器有关的特性（因此其行为是未定义的）。
- 限制递回、指标和中断的使用（这些容易出现错误）
- 不允许“非结构化的流程控制”，也就是非结构化的跳跃指令，例如Goto指令。

### 测试覆盖率

需要有适当的测试覆盖率，若安全等级越高，就需要用越严谨的测试框架。以下是DO-178C针对不同软件等级的需求：

- C级：指令覆盖率。在测试时“每一个指令至少执行过一次”。
- B级：分支覆盖率。“程式的每一个进入点和结束点都至少执行一次，程式中判断的所有可能结果都已进行过一次。”
- A级：修改条件判断覆盖（MC/DC）：分支覆盖的延伸，加上“判断中所有的条件都会独立影响判断的结果。”

### 独立性

软件安全标准一般会需要在要求一定程度独立性的情形下，进行特定流程活动，独立性可能是不同的人、不同主管底下的员工、甚至是独立组织。这避免利益冲突，也可以增加找到错误的可能性。

例如EN 50716的图2要求“实现者”、“测试者”（tester）和“验证者”（verifier）需是不同的人，“确认者”（validator）需是其他主管底下的员工，而“评估者”就是另一个部门的人。

DO-178C和DO-278A有要求一些活动（例如测试覆盖率的验证、保证活动等）要由具有独立性的人员进行，独立性定义为“责任的分工，以确保可以达成客观的评估。”

## 未解决的问题

### 软件失效率

在系统安全工程中，常会针对子系统或是元件的失效率订定上限。接着必须证明子系统或是元件的失效率不会超过分配的失效率，不然就要加上冗余或是其他容错机制。此作法在软件上不适用。

软件失效率无法准确预测。尽管软件可靠性领域已进行了大量研究（例如Lyu (1996)），但现有的软件安全标准没有要求使用其中任何一种方法，甚至是不鼓励使用，例如 DO178C（73页）中提到“许多基于开发指标预测软件可靠性的方法已被发表，例如软件结构、缺陷检测率等。本文档不提供这些方法的指导，因为在撰写本文时，现有方法尚未提供值得信赖的结果证明。”ARP 4761的4.1.2条款提到软件设计错误“和硬件失效不一样。硬件失效有失效率，而软件错误的几率无法量化。”

### Safety和security

软件安全性（Software safety）和保安（security，保证资讯只会被授权使用者使用，保证资讯不会被破坏）注重的层面不同。若安全相关的软件，可能会被修改盗用（secure相关问题），就可能会出现保安（security）的隐患。另一方面，有些保安（security）上的实务（例如频繁且定期的更新补丁），和已实务的安全实务相冲突（在已运作的系统要变更任何事务，都需要严谨的测试以及验证）。

### 人工智能

使用人工智能技术（例如机器学习）的软件，其生命周期和传统软件差异很大。相对于以传统方式开发的系统，上述软件的行为不容易预测。现今仍在探讨是否要在安全领域使用这类软件，以及如何使用。目前，相关标准普遍不认可人工智能和机器学习的应用。例如，EN 50716（表 A.3）指出，不建议在任何安全完整性等级中使用人工智能和机器学习。

### 敏捷开发方法

敏捷软件开发其特征是会有非常多次的迭代，有时仍被认为过于混乱，不适用于安全相关的软件开发。这一部分可能是因为敏捷开发宣言中提到的“可工作的软件胜过详尽的文件”。大部分软件安全相关标准是类似传统瀑布模型的生命周期，有些标准则允许更灵活的作法。DO-178C中提到“软件生命周期的过程可以是迭代的，即可以重复进入和重新进入。” EN 50716的附录C有说明如何使用迭代式的开发周期，同时符合该标准的要求。

## 相关条目

- 软件保证
- IEC 61508 - 电子/电机/可程式电子安全关键系统的功能安全
- ISO 26262 - 道路车辆 – 功能安全
- 功能安全
- 软件质量保证
- 系统意外

## 参考资料

此条目使用美军的 Software handbook 里的公开领域文件。