摘 要
近年来,软件开发中使用开源软件的比例越来越高,开源代码引起的一系列软件安全问题不容忽视。安全开发管控最重要的手段就是对源代码进行静态分析,当前的源代码静态分析技术主要包括语法分析、语义分析、数据流分析及控制流分析等,此类静态分析技术主要是针对缺陷类型构建分析模型,并不考虑开源代码漏洞问题。通过从开放漏洞数据库中抽取所有可用的漏洞记录,并从开源项目所在开源代码库中收集易受攻击的代码建立开源缺陷代码库,挖掘代码缺陷库中的缺陷匹配信息,并通过应用实例证明这是一种有效的源代码安全漏洞挖掘技术,具有较高的缺陷搜索匹配速度和准确性。
软件开发是一项复杂的任务,尤其是现在软件技术飞速发展,开发环境不断演变,软件架构和组成变得多样化。企业使用开源软件的比例越来越高,软件主要由自主开发代码、开源代码和开源组件组装而成。其中,开源代码、开源组件提供了必要的构建块,使组织能够交付价值、提高质量、降低风险并缩短上线时间。但同时其衍生出的软件安全管理问题也越来越多,软件团队只关注检测自主代码的潜在问题,往往忽视了对应用组件构成和应用所包含的开源代码中已知漏洞和开源协议的检查。
尽管安全人员和开发人员不断通过安全编码指南制定、软件测试和各种形式的代码审查等办法来提高软件质量和安全性,但通用漏洞披露(Common Vulnerabilities & Exposures,CVE)的数据记录显示,漏洞数量依旧呈增长趋势 。
鉴于软件的整体安全性高度依赖于软件漏洞的识别和缓解能力。因此,高效的分析代码中存在的漏洞可以帮助开发人员识别并修复源代码中的缺陷。
本文提出了一种自动发现源代码中安全漏洞的方案,通过从开放漏洞数据库中抽取所有可用的 CVE 记录,并从相关的开源项目所在的开源存储库中收集易受攻击的代码,建立开源缺陷代码库。利用搜索引擎与源代码分析规范多样化联合应用,根据不同结构的代码相似性特征,挖掘代码缺陷库中的缺陷匹配信息,具有较高的缺陷搜索匹配速度和准确性。
1
代码缺陷分析现状
1.1 静态代码分析技术
静态代码分析是白盒测试的一种方法,通过代码检查可以确定代码和设计的一致性、代码结构的合理性、代码编写的标准性和可读性、代码逻辑表达的正确性等。
静态代码缺陷分析是指在不运行目标程序的前提下分析目标程序(源代码或二进制)的词法、语法和语义等,并结合程序的数据流、控制流信息,通过类型推导、安全规则检查、模型检测等技术挖掘程序中的漏洞。
静态漏洞挖掘是常用的软件测试技术,在软件测试中占有非常重要的地位。具有代表性的 静 态 漏 洞 挖 掘 工 具 包 括:面 向 C/C++ 源 码的 Cppcheck、FlawFinder[3], 面 向 PHP 源 码 的RIPS,面向 Java 源码的 FindBugs,以及能支持多种类型目标对象的著名商业化漏洞检测工具VeraCode、Fortify、Coverity、Checkmarx等。另外,LLVM[5]、Clang[6] 等编译器也为软件源代码提供了大量的静态检测功能,从而在编译阶段实现对源代码的安全性检查。
1.2 问题分析
静态代码分析技术主要用于挖掘未知问题,发现潜在的不安全及不规范的代码,但是不涉及被测软件的运行及动态验证,这与漏洞扫描、渗透测试、病毒扫描等方面的技术原理完全不同,因此静态代码分析技术存在的误报问题往往给开发人员带来困扰,尤其是在信息系统频繁迭代开发场景下的多次检测会显著增加开发人员的工作量,开发人员或审计人员需要大量精力用于排除静态分析误报问题。
软件主要由自主开发代码、开源代码和开源组件组装而成。自主开发代码的缺陷是未知的,但是开源代码存在的缺陷却是公开的,因此,可以基于公开漏洞库,从开源项目所在的开源代码库中收集易受攻击的代码建立开源缺陷代码库,用于软件中开源代码的缺陷识别。相对于传统的静态代码分析,此技术路线具有较高的准确性。
2
开源代码缺陷识别系统
本文提出一种开源代码缺陷识别方案,能够快速准确地识别软件代码中存在的开源代码缺陷。通过抽取已知的开源代码中的缺陷信息构建缺陷知识库,利用搜索技术和代码分词多种规范化表达方式,在目标代码中可以有效地识别已知代码缺陷(精准搜索)和缺陷变体(相似搜索)。
开源代码缺陷识别系统架构如图 1 所示,系统分为缺陷数据处理流程、缺陷数据索引流程和缺陷代码搜索 3 个模块。
图 1 开源代码缺陷识别系统架构
2.1 缺陷数据处理流程
首先构建缺陷代码知识库,为了保障分析效果,知识库应包含多个级别的缺陷代码粒度,例如与缺陷代码相关的文件、类、函数等,并涵盖广泛使用的编程语言。本研究通过在 CVE记录中自动收集漏洞描述信息,挖掘托管在GitHub、GitLab 和 Bitbucket 以及开源项目自有代码管理库上的代码缺陷记录,收集易受攻击的代码样本。
CVE 数据信息主要来自美国国家计算机通用漏洞数据库(National Vulnerability Database,NVD),这是一个由美国国家标准与技术研究院(National Institute of Standards and Technology,NIST)维护的漏洞管理数据库。NIST 使用各种数据源发布整个 NVD 数据库供安全人员使用,漏洞数据包含漏洞源、安全检查、与安全相关的软件缺陷、错误配置、产品名称和缺陷影响。缺陷描述文件包含每日更新的 CVE 漏洞信息,对于较早期的缺陷信息描述,主要按照来源年份有序排列发布。
在 CVE 的描述文件中,每个漏洞都有 CVE-ID标 号、 发 布 日 期、 描 述、 关 联 参 考 链 接、 易受攻击的产品配置、通用缺陷枚举(Common Weakness Enumeration,CWE)缺陷分类和其他指标。每个漏洞的严重性都使用通用漏洞评分系统(Common Vulnerability Scoring System,CVSS)进行排名。CVSS 由 3 个指标组成,即基础、时间和环境,漏洞的特征和上下文信息。漏洞影响评分系统存在两个版本:CVSSv2 和CVSSv3,它们都对缺陷进行细致描述。CVSSv3为 CVSSv2 的升级描述,用来更准确地对漏洞进行影响评分,并提供更多信息来区分不同类型的漏洞。当开源项目中的漏洞被修复时,CVE 记录信息将更新,增加一个或多个指向相关源代码存储库的引用,包括修复缺陷时提交记录生成的哈希。这些信息可用来在本研究中作为代码缺陷库的组成信息。缺陷数据处理流程如图 2所示。
图 2 缺陷数据处理流程
2.1.1 收集 CVE 记录信息
采集工具从 NVD 服务器检索所有已发布的JSON 格式的漏洞源,搜集范围包括 2002 年首次发布到收集之日最后一次发布的 CVE。然后对获取到的 JSON 文件进行聚合、加工和处理,滤掉 CVE 记录中所有在 reference 字段中没有与之关联的修复程序 CVE 记录信息,因为这些 CVE无法收集相应的易受攻击或已修复的代码。在处理和过滤完缺陷记录后,CVE 记录信息包括CVE-ID、发布日期、最后修改日期、参考数据、CVSS 严重性评分、漏洞影响和范围、可利用性评分等漏洞的描述。
通常,CVE 缺陷类型由 CWE 进行分类,因此还需要收集这些 CWE 类型的详细信息,并将它们与适当的 CVE 记录进行映射,用来区分具体的缺陷类型。
2.1.2 修复记录提取
在分析 CVE 缺陷记录信息时,只分析存在修复记录的 CVE,通过提取修复 CVE 记录信息中与代码相关的开源仓库信息,利用 git 工具在本地克隆代码项目,并根据 CVE 记录中提交的哈希值,通过 git 来收集有关易受攻击的缺陷代码信息,包括代码的语言、版本、发布时间、CVE 记录、CWE 记录、存储库地址信息、提交记录、受影响的文件和受影响的方法等信息,并将收集到的信息存储在数据库中。
2.1.3 构建元数据信息
CVE 中涉及开源项目相关的代码库信息主要来自 GitHub、GitLab 和 Bitbucket,其中项目所属 GitHub 的比例最高。在抽取缺陷代码信息过程中,需要在缺陷数据库中覆盖代码仓库的项目基本信息,例如存储库名称、描述、创建日期、最后推送日期、主页、编程语言、分支数和星数等指标,这些信息可作为过滤数据的参数,例如星数大小是关注项目成熟度的一个重要评判指标,即星数越大的项目,成熟度越高。
2.1.4 缺陷代码提取
一 般 来 说, 只 要 修 复 了 开 源 代 码 漏 洞,CVE 描述记录就会包含存储库的统一资源定位符(Uniform Resource Locator,URL), 利 用 抽取到的缺陷修复提交时生成的哈希和地址信息,通过 git 即可在本地克隆开源代码项目,并根据哈希信息抽取修复之前和之后的代码信息,这些信息包括缺陷修复时所涉及的代码文件和代码片段。其中提交信息中的每个条目可能与一个或多个 CVE 相关联。提交的信息还包括作者、时间和日期、提交的描述消息等内容。
与缺陷相关的文件信息主要包含更改前后的文件内容,以及在 git 提交过程中生成的 diff信息。此外,还需要收集一些元数据,例如文件名、新旧路径、修改类型(即添加、删除、修改或重命名)、在该文件中添加或删除的行数、代码行数变化等。
提取修改后的代码片段,与抽取文件级别的更改过程相似,利用 git 工具抽取代码片段的变更信息。除代码外,涉及的数据信息,例如片段所在的方法名称、其签名性质、参数、方法的开始行和结束行、代码行数等作为方法元数据信息也会被抽取出来。
为了更好地识别文件和代码片段使用的具体编程语言信息,识别过程通过 linguist[8] 来检测给定代码内容中使用的实际编程语言。
2.2 缺陷数据索引流程
提取缺陷代码后,需要对缺陷数据加工处理,存入数据库中,形成缺陷代码知识库,供查询模块使用。缺陷数据索引流程如图 3 所示。
图 3 缺陷数据索引流程
2.2.1 前端解析
所有的代码信息都要经过编译处理,用来从程序代码中获取函数信息并分析其词法,但如果源代码不完整或包含语法错误,将会影响整个解析过程。因此,为了保障分析的可靠性,采用 antlr4 完成代码词法解析,解析过程不需要代码编译构建环境,能够解析单个代码文件,并且在解析过程中遇到语法错误时不会失败,即使被测代码不完整,也会兼容错误分析,保障解析顺利通过。
2.2.2 预处理规范化
整个数据索引和后边的缺陷查询过程均以代码片段为基本单元,查询过程中需要考虑代码相似问题,如图 4 所示,如下代码可能会存在 4 种变种情况。
图 4 原始代码片段
Type-1:精确相似。被检测代码去掉空格、回车、注释等与代码无关信息后,与缺陷代码保持一致。如图 5 所示,与原代码相比,代码片段仅少了回车、空格信息。
图 5 Type-1 代码片段
Type-2:重命名相似。与被检测代码中缺陷代码相比,除了类型、标识符、函数名、注释和空格的修改,其他信息保持一致。如图 6所示,与原代码相比,代码片段中的方法名、参数类型做了部分修改,其他信息保持一致。
图 6 Type-2 代码片段
Type-3:重组相似。即被检测代码与缺陷代码相比,存在进一步的结构修改(例如删除、插入或重新排列语句)。如图 7 所示,代码片段增加了几条新的语句。
图 7 Type-3 代码片段
Type-4:语义相似。被检测代码与缺陷代码在语法实现上完全不同,但实现的最终功能相同。如图 8 所示,代码片段实现的功能与图 4相同,但是语法表示方式已经完全不同。
图 8 Type-4 代码片段
Type-4 语义相似目前很难通过代码相似查找实现,故暂不在本研究的范围之内。本次只考虑 Type-1、Type-2、Type-3 型查询。为了获取更好的查找效果,需要对分词的相似度进行规范化处理。在预处理阶段,为了更准确地找到缺陷代码及其变种,需要从目标源代码中提取代码块并将其转换为 token 序列,进行重组规范化,这里采用 n-gram 实现分词重组。对于n 而言,选择一个大的数量原则上存在更长的重叠区域,并且携带更多单词信息,精度会更高一些,但是会严重影响处理 n-gram 所需的内存和磁盘 I/O时间。相反,选择小的 n-gram 允许更大的间隙和更好的匹配灵活性,并且需要更少的内存和磁盘访问时间,但也会导致检索出缺陷代码片段的概率更高,因此需要找到一个合适的 n 值,在查找速度和结果精度上得到平衡。
首先定义一个包含 a0、a1、a2 及 a3 的数组:
(1)原始表示 a0:一个 token 序列,代表了原始代码片段信息。
(2)Type-1 表示 a1:包含来自原始代码的标记的 n-gram 的 token 序列,其为原始代码token 序列的组合。
(3)Type-2 表示 a2:包含来自原始代码的标记的 n-gram 的 token 序列,其中原始代码token 序列中的标识符、文字和类型标记被代表标记替换。
(4)Type-3 表示 a3:包含来自原始代码的标记的 n-gram 的 token 序列,除字符 {、}、[、]、(、) 和;外,其他的全部按标准替换处理。标点符号未标准化,因为它们对代码结构顺序有着重要意义。
通过调试分析,当 n 值为 4 时,工具表现出了良好的性能。因此,当预处理模块中的 4个代码表示为 a0 时,则表示为原生分词,不做任何排序组合;a1、a2 和 a3 则表示选择了 4-gram。3 个基于 n-gram 的表示 (a1,a2,a3) 是从原有的函数方法内容中演变而来。通过预处理模块的加工组合,将原有的代码结构进行了规范化,从而使其更适合代码搜索。
token 规范化表示类型如表 1 所示,其中 D代表数据类型,J 代表类名,K 代表关键字,P代表包,O 代表运算符,S 代表字符串文字,V代表数字,W 代表变量。a2 中所有标识符、类型、数字和字符串文字分别被代表标记 W、D、V 和S 替换。a3 中所有的分析都替换为它们各自的代表标记形成规范化分词序列。
表 1 token 规范化表示类型
以图 9 的代码片段为例,规范化以后的分词序列生成的内容如图 10 ~图 13 所示。
图 9 代码片段样例
图 10 a0 规范化
图 11 a1 规范化
图 12 a2 规范化
图 13 a3 规范化
这种预处理能够保障在搜索期间查询的代码关键信息与索引中代码片段的表示相匹配。另外,在索引和查询阶段都会用到预处理规范化技术:在索引阶段,搜索引擎为给定的代码片段创建一个新文档,并将 4 个表示放在文档内的单独字段中,然后将文档存储在搜索索引中。在查询阶段,通过预处理将查询内容加工为一个组合查询,组合包含 4 种关键字组成的子查询序列。
2.2.3 缺陷数据索引
数据存储采用非关系索引数据库工具 Zinc,其具有索引功能,也是一种轻量级的搜索引擎,能够满足不同用户的各种搜索需求,为所有类型的数据提供近乎实时的搜索和分析。对于结构化或非结构化的文本、数字数据及地理空间数据,都能够以快速搜索的方式高效地存储和索引数据。
建立缺陷数据索引的过程主要是对提取的开源代码数据信息进行加工处理。整个流程为:将预处理加工过的规范化序列存储到 Zinc 数据库中,Zinc 会生成反向索引,索引包括一组在document 中出现的唯一单词及单词所出现的位置。索引建好后,可以通过 Zinc 所支持的文件和方法两种类型的代码完成查询,对于完整的代码文件,将代码文件序列化后,以 a0 方式存入到数据库中。对于文件中的方法,预处理后生成 4 种规范化标识表示,这些规范化表示可以捕获不同级别的代码结构,能够有效地识别出缺陷代码和缺陷变种。
2.3 缺陷代码搜索
缺陷代码搜索主要利用分词规范化和搜索引擎自身的索引查询功能来搜索代码中是否存在缺陷信息,在缺陷知识库中搜索通过预处理后生成的关键字信息,并利用分词规范化来提高代码缺陷搜索的精度和相似匹配的灵活性。缺陷代码搜索如图 14 所示。
图 14 缺陷代码搜索
当用户提交待查询的代码后,首先对代码进行词法解析和预处理,这个过程与索引阶段采用相同的方式。预处理结束后,一个序列化后的代码查询序列被发送到预处理模块,生成4 种查询关键字,利用 Zinc 检索功能,通过关键字检索组合缺陷库中的索引信息,匹配命中信息,并将最后的结果报告返回给用户。
3
实 验
本文通过搜索技术实现了一种开源代码缺陷识别系统,通过一个实例来验证系统的有效性。
在大多数情况下,各种 Linux 发行版默认提供的内核都运行稳定,但有些时候必须重新构造和定制内核来满足实际需求,例如,系统中加入了当前内核不支持的或者尚未启用相应功能的硬件,或者物联网设备操作系统、Android移动操作系统等都需要完成 Linux 系统的定制迁移。
Linux 各种主要发行版本中由供应商提供的内核往往明显落后于最前沿的技术,而且它们的更新很不及时,这就导致系统中可能存在既有的安全风险。
CVE-2016-5195[9] 是 Linux Kernel 中的条件竞争漏洞,攻击者可以利用 Linux 内核中的写入复制技术中存在的逻辑漏洞完成对文件的越权读写。具体细节为:Linux 内核的内存子系统在处理写入复制(Copy-on-Write)时产生了竞争条件(Race Condition)。恶意用户可利用此漏洞来获取高权限,对只读内存映射进行写访问。竞争条件是指任务执行顺序异常,可导致应用崩溃,或令攻击者有机可乘,进一步执行其他代码。攻击者可利用这一漏洞提升目标系统权限,甚至可能获得 root 权限、代码,如图 15 所示。
图 15 CVE-2016-5195 缺陷代码
Linux 发行版本,如红帽、Debian 和 CentOS,已经发布了更新来解决内核上存在的问题,但是很多由公司维护的移动操作系统却没有更新该内核漏洞。使用本文提出的源代码安全漏洞挖掘技术分析 Android 7.0、Android 6.0.1、Android 6.0 源代码,均发现了系统中存在着 CVE-2016-5195 漏洞,如图 16 所示。
图 16 CVE-2016-5195 缺陷代码命中结果
对于变种的缺陷,工具依旧保持较高的准确 度,CVE-2005-0504 漏 洞 [10] 如 图 17 所 示,未进行正确的长度检查可能导致数据缓冲区溢出漏洞,本地攻击者可以利用这个漏洞提升特权。
变 种 后 的 代 码 片 段 如 图 18 所 示, 其 为CVE-2005-0504 漏洞代码的变种,对函数名和部分参数做了重命名,但是代码结构与原存在缺陷代码一致,工具能够精准地识别并告警,CVE-2005-0504 缺陷代码命中结果如图 19 所示,表现出了弹性兼容识别代码变种的能力。
图 17 CVE-2005-0504 代码缺陷
图 18 变种后的 CVE-2005-0504 代码片段
图 19 CVE-2005-0504 缺陷代码命中结果
4
结 语
静态代码分析系统在安全开发领域得到了越来越广泛的应用,本文在主流源代码静态分析技术的基础上,提出了一种自动发现源代码中安全漏洞的方案,通过从开放漏洞数据库中抽取所有可用的 CVE 记录,并从相关的开源项目所在开源存储库中收集易受攻击的代码建立开源缺陷代码库。通过搜索引擎与源代码分析规范多样化联合应用,利用不同结构的代码同源性特征,挖掘代码缺陷库中的缺陷匹配信息,并通过应用实例展示了该技术研究的可行性,验证了该系统具有较高的缺陷搜索匹配速度和准确性。下一步,可研究扩大漏洞采集的范围,涵盖 CVE、中国国家信息安全漏洞库(China National Vulnerability Database of Information Security,CNNVD)及主流社区漏洞库的开源代码漏洞,同时优化分词规范化算法,以提高源代码缺陷的检测精度。
引用格式:张勇 , 张合磊 , 赵平 . 一种开源代码缺陷识别系统的实现 [J]. 信息安全与通信保密 ,2023(7):70-82.
张 勇,男,硕士,高级工程师,主要研究方向为网络安全;
张合磊,男,硕士,高级工程师,主要研究方向为源代码静态分析、安全开发、软件供应链安全;
赵 平,男,硕士,高级工程师,主要研究方向为源代码静态分析、安全开发、软件供应链安全。
推荐站内搜索:最好用的开发软件、免费开源系统、渗透测试工具云盘下载、最新渗透测试资料、最新黑客工具下载……
还没有评论,来说两句吧...