软件安全知识之预防漏洞

admin 2023年5月20日01:35:14评论67 views字数 2310阅读7分42秒阅读模式

软件安全知识之预防漏洞

预防漏洞

一旦一类漏洞被很好地理解,一个重要的问题是如何防止在软件中引入此类漏洞,或者至少降低这种漏洞的可能性。最有效的方法通过设计编程语言或API来消除漏洞类别。

总体思路如下。我们在主题1中看到,许多类别的实现漏洞可以被描述为违反某些子组件的规范。我们称违反此规范的软件系统的执行、错误执行或有错误的执行。从安全角度来看,区分导致立即终止执行的错误(捕获的错误)和可能在一段时间内未被注意到的错误(未捕获的错误)很有用[16].未捕获的错误特别危险,因为在未捕获错误之后软件系统的进一步行为可能是任意的,攻击者可能能够将软件系统引导到违反安全目标的行为。因此,设计语言或API以避免错误,尤其是未捕获的错误,是防止漏洞存在的有力方法。例如,像Java这样的语言实际上使得不可能引入内存管理漏洞:静态和动态检查的组合确保不会发生未捕获的内存管理错误。这有效地防止了1.1中讨论的攻击技术。但是,重要的是要注意,这并不能防止内存管理错误的存在:程序仍然可以越界访问数组。但该错误不再是漏洞,因为当发生此类访问时,执行会立即终止。有人可能会争辩说,如果软件系统的安全目标之一是可用性,包括缺乏意外的程序终止。

在无法选择或重新设计编程语言或API本身的情况下,可以通过实施安全编码来降低特定类别的漏洞的可能性实践。

本主题概述了这些可以防止引入漏洞的技术。

语言设计和类型系统

编程语言可以通过以下方式防止可被描述为违反规范的实现漏洞类别:

1. 使在语言中表达规范成为可能,以及

2. 确保在表达的规范方面不会出现未捕获的执行错误。

内存管理漏洞

编程语言规范本质上包括该语言提供的所有内存分配、访问和释放功能的规范。因此,内存管理子组件的规范始终可用。如果语言定义暗示不存在未捕获的内存管理错误,则编程语言称为内存安全语言。像C或C++这样的语言不是内存安全的,因为语言定义允许实现可能具有未捕获的内存管理错误的语言,但即使对于此类语言,也可以构建特定的内存安全的实现(通常以牺牲性能为代价)。

可以通过以下组合使语言具有内存安全性:

1. 精心选择它支持的功能:例如,语言可以选择避免可变状态,或者可以选择避免动态内存分配,或者可以选择依靠垃圾回收来避免手动释放,

2. 强制实施动态检查:例如,强制要求每个数组访问都必须进行边界检查,以及

3. 实施静态检查,通常以静态类型系统的形式:例如,可以通过类型系统保证对象字段访问的安全。

编程语言在如何组合功能、动态和静态检查方面差异很大。像Haskell这样的纯函数式语言避免了可变内存,并严重依赖静态检查和垃圾回收。像Python这样的动态语言严重依赖动态检查和垃圾回收。静态类型的面向对象语言(如Java和C#)介于这两个极端之间。像SPARK(Ada的一个子集)[19]和Rust这样的创新语言在不依赖垃圾收集的情况下实现了内存安全。例如,Rust使用一种类型系统,允许编译器静态地推理指针,从而使它能够在已知不再可访问的位置插入代码以释放内存。这是以降低程序代码的活性为代价的。

结构化输出生成漏洞

结构化输出生成漏洞的一个重要原因是程序员将输出的预期结构隐式保留,并通过字符串操作计算结构化输出。编程语言可以通过提供语言功能来帮助防止此类漏洞,这些功能允许程序员明确预期结构,从而提供规范。然后,语言实现可以确保不存在与该规范相关的未捕获错误。

第一种方法是提供支持结构化数据描述的类型系统。这种方法已经针对XML数据进行了严格的制定:编程语言支持XML文档作为第一类值,正则表达式类型[20]支持。使用标准正则表达式运算符的XML文档结构的说明。输出给定类型的XML文档的类型正确程序保证生成类型描述的结构的XML输出。

第二种方法是为结构化输出生成的一些常见用例提供原始语言功能。语言集成查询(LINQ)是C#语言的扩展,具有用于编写查询表达式的语法。通过将查询编写为表达式(而不是通过连接字符串来生成SQL查询),查询的预期结构是显式的,并且LINQ提供程序将查询编译为SQL可以提供生成的查询具有预期结构的有力保证。

争用条件漏洞

堆分配内存上的争用条件漏洞通常通过别名(存在指向同一内存单元的多个指针)来启用。如果两个并发线程都保存同一单元的别名,则该单元上可能存在争用条件。混叠的存在还会导致临时内存管理漏洞,即通过一个别名释放内存,但随后通过另一个别名访问内存。所有权的概念有助于减轻由于别名而产生的复杂性。这个想法的本质是,虽然一个资源的多个别名可以存在,但这些别名中只有一个是资源的所有者,并且某些操作只能通过所有者执行。所有权制度对如何创建别名以及允许通过这些别名执行哪些操作施加了限制。通过这样做,所有权制度可以防止争用条件漏洞,或者它可以支持自动内存管理而无需垃圾收藏家。例如,堆分配内存单元的简单所有权制度可能会施加以下约束:

(1)只有在保证别名在所有者之前超出范围时,才能创建别名,

(2)别名只能用于读取,以及

(3)所有者可以仅当当前不存在别名时才写入单元。

这种简单的制度避免了数据竞争:永远不会在同一单元上进行并发读取和写入。它还支持无需垃圾回收的自动内存管理:一旦所有者超出范围,就可以解除分配堆单元。当然,这种简单的制度仍然具有相当的限制性,并且存在大量关于设计限制较少的所有权制度的研究,这些制度仍然可以提供有用的保证。

所有权制度可以通过类型系统由编程语言强制执行,并且一些研究语言已经这样做,目的是防止数据竞争或内存管理漏洞。Rust编程语言是一种最新的系统编程语言,是第一个包含所有权类型系统的主流语言。

原文始发于微信公众号(河南等级保护测评):软件安全知识之预防漏洞

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年5月20日01:35:14
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   软件安全知识之预防漏洞https://cn-sec.com/archives/1748941.html

发表评论

匿名网友 填写信息