在软件开发生命周期(SDLC)的测试或验证阶段,不同的企业因为团队或者业务模式的区别而选择不同的做法和设计,单一的安全验证流程并无法满足所有的测试场景或验证场景。

比如,有的企业会有测试环境、预生产环境和生产环境,有的则只有测试环境和生产环境,有的甚至还会细分到开发人员本地的单元测试环境;测试环境的构建中,有的团队会要求开发人员本地测试通过后构建Docker镜像包,再通过诸如SonarQube等测试工具进行镜像测试同步到公司DockerHub,最后再进行测试环境部署,而有的团队则是开发人员只负责代码的编写,剩余的镜像构建和发布等都是通过运维团推或运维平台完成。

由于CI/CD(持续集成/持续发布)设计和机制的不同,不同的团队对于持续集成期间测试的方式也会有不同。

但有一个方面是共性的,即在持续集成期间的测试,不仅仅强调安全测试,也会强调功能测试,甚至功能测试更容易被企业内不同角色的人所理解,因此测试岗位的设立和工作的开展会早于安全岗位和安全测试工作。

在这种情况下,安全测试工作的自动化程度不能低于功能测试,当功能测试更多靠自动化完成的时候,安全测试结果推迟再同步到研发团队,不仅会影响安全漏洞的修复,也会影响研发团队对于安全工作的重视程度,毕竟修复漏洞的工作多数最终仍然需要研发人员的介入,或者说,安全测试或安全验证的工作节奏和频率需要和测试工作基本一致,在功能测试期间,程序的部分功能可能存在阻碍性缺陷(Bug)导致无法正常完成功能测试,而当这部分缺陷修复之后开始第二轮功能测试时,安全验证和测试需要同时开展,但人工验证和测试的工作量实际汪汪会比功能测试的测试用例工作量大许多,所以在当下的安全验证阶段,自动化的安全验证手段会成为必然。

在微软的SDL模型中,验证阶段的主要工作包括动态程序分析、模糊测试(Fuzz)和威胁模型/攻击面评析。这是由微软自身产品的定位所决定,作为绝大多数产品是桌面产品的特性,模糊测试是一种常见的漏洞测试方法。而对于Web应用、移动应用,这种测试方法可应用的场景不多(比如针对API的模糊测试),因此测试手段的选择需要根据自身应用的特点,选择合适的安全测试方法。

以下是当前常见的安全测试方法的介绍,以及相应的优缺点:

SAST(Static Application Security Testing)

SAST使用了一种完全白盒的方法,即在不执行的情况下对源代码进行扫描。整个代码库都会被搜索到可疑的模式和危险的函数使用,这可能表明存在潜在的漏洞。

优势:

  • 提供了最大的代码覆盖率,能够使整个代码库被扫描。
  • 不需要可执行的代码,它可以在软件开发生命周期(SDLC)的任何阶段使用。

劣势:

  • SAST最大的优势(白盒方法)也是它最大的劣势,因为它需要访问源代码。
  • 由于SAST不执行代码,所以它无法发现运行时的问题。在需要用户输入或外部库的地方,它也不是一个好的选择。
  • SAST会产生大量的假阳性/阴性。大型和复杂的项目将很容易产生成千上万的警告,需要手动审查。

SCA(Software Composition Analysis)

SCA与SAST类似,但是,它的主要目标是识别代码库中的所有开源组件、库和依赖关系,并将该清单映射到当前已知的漏洞列表中。

DAST(Dynamic Application Security Testing)

在DAST中,源代码被编译、执行,然后在运行时进行扫描,以寻找安全漏洞。随机和预定的输入被传递给被测试的应用程序,如果应用程序的行为与预定的正确响应不同,或者程序崩溃,就会记录一个警告,这意味着应用程序中的一个错误已经被发现。

优势:

  • 由于应用程序的行为是被分析的,所以(几乎)没有误报。
  • DAST用于发现运行时问题,当需要用户交互时,它是正确的选择。
  • DAST不需要被测应用程序的源代码(黑盒方法)。

劣势:

  • DAST需要一个工作中的应用程序来测试。
  • 由于没有任何东西可以指导随机输入的生成,DAST不能提供良好的代码覆盖率,而且效率很低。
  • 很难将发现的错误映射回源码中去修复问题。

IAST(Interactive Application Security Testing)

IAST是两者的混合版本,结合了SAST和DAST的优点。

动态方法(DAST)常用于测试和过滤掉SAST产生的警告,以提高应用安全测试的准确性。测试指令可以像DAST一样确认利用成功,提高其性能,并像SAST一样对应用源码进行代码覆盖。

FAST(Feedback-based Application Security Testing)

纯DAST解决方案和黑盒测试,一般来说,代码覆盖率较低,因为它们依靠随机的、基于模式的或蛮力的方法来生成输入和测试案例。

边缘模糊采用基于反馈的(覆盖指导)模糊技术,对被测试的软件进行仪器化测试,以识别漏洞和错误;它可以通过反向工程(如果应用程序是闭源的)来补充。在模糊过程中,随机输入 “发送到 “被测软件,同时监控其行为,直到触发崩溃。然后记录和分析导致崩溃的输入,以获得可用于利用(或修复)应用程序中的错误的信息。

当执行每个输入时,模糊器会得到关于所覆盖代码的反馈,使突变引擎能够测量输入质量。突变引擎的核心是用于优化代码覆盖率的遗传算法,作为一个健康函数。生成的输入导致新的代码路径(或基本块或边缘;取决于使用的模糊覆盖度量),最大限度地提高代码覆盖率,从而增加触发bug的概率,这些输入被优先考虑,并在下一批突变过程中使用。

优势:

  • FAST几乎不会产生误报,如果模糊器发现了什么,通常是确认的问题。
  • FAST会自动将代码覆盖率最大化,并且是高度自动化的。一旦模糊器启动并运行,它就可以搜索错误,而不需要进一步的人工交互。
  • 根据模糊器的类型,可能不需要源代码。

劣势:

  • FAST需要一个工作的应用程序来测试。
  • FAST需要特殊的专业知识(如编写线束)和测试基础设施。

实际测试方法及相应工具的应用涉及到DevSecOps,这里不做过多介绍。

在安全验证阶段再次加入威胁模型和攻击面评析实践,是由于应用开发过程中,由于开发人员的实现和实践不同,应用程序结果常常会与软件需求和设计之初所设定的功能和设计规范不同,因此需要在应用开发完毕后重新评估其威胁模型和攻击面,具体措施就是对照设计期间设定的威胁模型和攻击面,对应用程序进行重新评估,确保应用程序的实现符合设计规范,或者预期外的设计能够被及时发现并被缓解。

在同一应用程序的多次迭代、验证过程中,随着开发团队安全能力的提升以及应用程序安全状况的转变,可以将威胁模型和攻击面分析过程抽象为应用程序安全测试基线,该基线的目的就是通过人工逐条核对,加快评析的过程。

软件开发过程相比其他工程是看不见、摸不着的,其过程中的产品设计、系统设计、程序设计等等都会如同安全设计一般出现前后不一致的情况,比如产品设计是在墙面上打个洞,最终的实现结果可能是墙面上的一颗钉子。因此,在每一次的产品发布之后存在的事件或事故,都需要针对整个产品过程进行复盘和分析,确保SDL的各个环节能够不断更新和改进,正如本文开头所述,不同的企业和团队会形成自己的风格、流程和方法的产品周期。