中国领先的IT技术网站
|
|

利用静态分析加固开源入侵检测系统(IDS)的最佳实践

本文将介绍Coverity的静态代码分析是如何在不同部署场景中,被用来扫描那些组成安全洋葱(Security Onion)发行版的软件包。

作者:陈峻译来源:51CTO.com|2017-10-13 18:33

Tech Neo技术沙龙 | 11月25号,九州云/ZStack与您一起探讨云时代网络边界管理实践


【51CTO.com快译】入侵分析人员使用网络安全监控(NSM)的原理来保护计算机系统。NSM是“在对各种入侵进行检测和响应过程中,所涉及到的标识和警告环节的收集、分析和问题升级”。NSM的核心功能包括入侵检测系统(IDS),基于网络的IDS(NIDS),主机入侵检测系统(HIDS)和物理入侵检测系统(物理IDS)。分析人员在部署之前应当评估诸如IDS和HIDS的软件包。

SCA

我们可以用许多不同的方法来评估给定软件包的安全水平,而其中的一种是使用Aberlarde安全系统工程法。这种方法在软件开发生命周期(SDLC)的各个阶段详细评估了商业和开源软件包的安全特性。检查开源软件的优势在于可以直接访问它们的代码。通过这种直接访问的方式,开发人员可以使用诸如代码检查和静态代码分析的各种技术。

静态代码分析(SCA)是在不执行软件本身的情况下找出代码问题的一种方式。为实现这一目的,SCA的相关工具通过使用各种可能的输入数据,来模拟代码执行的不同分支可能性。SCA工具能兼顾发现质量方面

(如COPY_PASTE_ERROR,FORWARD_NULL,INCOMPATIBLE_CAST)和安全方面(如UNINIT,BUFFER_SIZE和USE_AFTER_FREE)的问题。SCA工具同时也能提供一些特定的修复,以便开发者应用到源代码上,来减少软件的缺陷密度。它是通过组件的大小(通常是代码的指定行数)除以缺陷的数量,来计算出缺陷的密度。在2014年,开源软件的平均缺陷密度为0.61每一千行代码或称KLOC。相比之下,商业软件的缺陷密度则为0.76每KLOC。

我们有许多源自OWASP的静态分析工具可供选择。自从Coverity扫描服务面世以来,该公司在过去的十年里备受瞩目。开源开发者们免费将他们的代码提交到Coverity基于云服务的扫描服务上,以进行分析和检查。Coverity还可在客户的本地环境中部署一个商业产品,以提供各种相同的分析工具。本文将介绍Coverity的静态代码分析是如何在不同部署场景中,被用来扫描那些组成安全洋葱(Security Onion)发行版的软件包。

安全洋葱

安全洋葱是由Doug Burks维护的一个Linux发行版,其中包括完整的数据包捕获、NIDS、HIDS和一整套分析工具。这些工具包括:

  • netsniff-ng:用于全量数据包的捕获
  • Snort、Suricata和Bro for NIDS
  • OSSEC for HIDS
  • Sguil、Squert、Snorby、and ELSA:用于数据分析

与单独配置每个工具相比,使用安全洋葱发行版可以节省时间。在着手使用该发行版进行开发之前,请遵循Burks 2016来安装、配置和更新安全洋葱。一旦完成之后,开发人员就可以检查安全洋葱软件包的源代码,以发现各种安全漏洞。

Coverity扫描

Coverity的首个部署选项是Coverity扫描。Coverity扫描是一种云服务,也是一个免费的开源社区,已注册的开源开发者可以上传他们的源代码用作分析。Coverity的静态分析引擎随即执行对源代码的分析。之后,开发们就可查看结果报告中的各种问题,并遵循给出的建议来解决问题,然后再重新提交源代码。

Coverity扫描的实例:Wireshark

在使用Coverity扫描时,开发人员一般遵循四个步骤:构建、分析、提交缺陷和审查结果。在构建阶段,原始的构建命令被作为参数传递给Coverity的命令行:cov-build工具。cov-build的指令运用带有—dir的标记,在中间目录下进行原始构建和存储信息。让我们以Wireshark为例,来看看Coverity的如下编译命令:

  1. $ cov-build --encoding UTF-8 \ 
  2. --dir ~/cov-inter-wireshark make 

在分析阶段,中间目录被手动、或一个连续集成系统(如 Travis-CI)上传到Coverity的扫描处。代码分析是在Coverity服务器上进行的,而并非开发人员的本地系统之上。Coverity将自动处理提交缺陷的阶段。通过登录到Coverity连接的网络接口,各个缺陷将在源代码的行内显示出审查的结果。

Wireshark项目拥有着Coverity扫描的一批活跃用户。自2006年以来,他们修复了数以千计的缺陷。如图1所示,软件的缺陷密度非常低,只有0.26每KLOC。

Coverity扫描:Wireshark (https://scan.coverity.com/projects/wireshark)

图1:Coverity扫描:Wireshark (https://scan.coverity.com/projects/wireshark)

Coverity的本地分析

相对于Coverity扫描的云服务而言,开发者也可以选择购买Coverity的商用产品。商业产品可以本地模式运行在他们的网络之中。一个标准的Coverity部署要用到两台机器,来构成客户机/服务器架构。

安全洋葱一般作为本地开发主机,以客户端的方式将其结果发送到Coverity的数据库服务器上。默认情况下,安全洋葱的软件包以可执行文件的形式被安装。开发人员必须事先下载它,然后编译并分析相应的源代码。

开发人员在客户端主机上执行代码分析,而并非使用Coverity扫描的服务器。存储结果的数据库是在本地网络上,而不是在Coverity扫描的服务器上。如图2所示,通过登录到Coverity的Web服务器,并选择合适的项目(如 Wireshark),便可浏览到各种不同的结果。

Coverity的项目菜单

图2:Coverity的项目菜单

如图3所示,一旦选中了某个项目,就可以继续选择Coverity的菜单(三道线的图标),并选择“高危安全风险”。

高危安全风险过滤器

图3:高危安全风险过滤器

这张图将所有的Coverity缺陷过滤到了一个仅包括安全问题的较小列表之中。

修复安全漏洞

在修复代码之前,让我们来看看如何对软件使用“不伤害原则(do no harm rule)”,以及如何将编译器的警告纳入静态分析的体系中。

不伤害

“学写整洁的代码并不容易”。在开始的时候,源代码可能是整洁的,但随着时间的推移它会变得“越来越杂乱”。对于一个优秀的开发人员而言,既要会写源代码,也要会阅读。如果不熟悉代码的读与写,入侵分析人员将会面临艰巨的挑战。

“我们可以将美国童子军的一个简单规则运用到我们的专业领域:在离开营地时,将其打扫得比你发现它时更干净。如果我们都能在代码签入时,使其比被签出时更加整洁,那么代码就会不朽了。”。

“不伤害原则”有两个好处:开发人员能提高自己的编程技巧,同时原创作者也会认可开发者是负责任的披露(responsible disclosure)。

编译器的警告

静态代码分析的另一个方面是编译器的警告。人们常重视代码是否能编译通过,而忽视了编译器的各种警告。我们以daq-2.0.6程序包为例,文件daq_afpacket.c的第859行声明了一个变量rc:

  1. int rc

第866行包含了:

  1. rc = send(instance->peer->fd, NULL, 0, 0) 

而编译器的警告是:

  1. daq_afpacket.c:859:25: warning: variable ‘rc’ set but not used  
  2.     [-Wunused-but-set-variable]                      int rc 

编译器会告知开发人员:来自调用函数send()的返回值设置了变量rc,但是rc并没有在后面的函数中被使用到。因此一种解决方案是:删除第859行,并将第866行改为:

  1. (void) send(instance->peer->fd, NULL, 0, 0) 

这种修改屏蔽了编译器警告,并尽可能地贴近原始代码。通过将send()的返回值调用分配给(void),目前的代码就会忽略它了。另一种可能性的解决办法是:在第866行后,添加额外的代码,以检查rc所有的返回值。这样修改了程序的执行,因此需要由维护人员进行审查。

编译器也具有“视警告为错误”的能力。如果开启了此功能,则会有益于在分阶段的项目中引入编码的规则。开发人员能够一次只开启一个警告,逐个修复,之后在时间允许的情况下,再打开额外的警告。比如:在Adobe Photoshop中,编译器就具有开启“视警告为错误”的选项,以使开发团队提高整体发现能力。如果在构建系统时连续出现新的编译器警告,并有构建的失败,那么团队就能迅速发现这些错误。开启“视警告为错误”的另一个原因是:尽量减少各种静态分析的缺陷,从而在添加其他工具之前,通过编译器的帮助,更好地在代码层面上消除那些缺陷。

Coverity的各种安全检查

Coverity的7.7版本有着七十多种适用于C和C++的检查,其中有十八项是注重安全问题的。本节将重点介绍UNINIT,BUFFER_SIZE和USE_AFTER_FREE。

1. UNINIT

在ANSI C语言中,“变量的初始内容是不确定的”。由于该语言允许各种变量在定义时不被初始化,因此经常有大量的没有显式初始化的变量在C语言代码中。一些代码在变量声明之后被立即赋值,因此完成了初始化。而有时,编译器会自动将变量赋值为零。因此开发人员必须记住这些规则,这也就给软件编程留下了安全隐患。虽然已有针对C语言该问题的解决办法,但现如今,对于开发者来说还是需要记住这些规则的。

消除这些问题的一种方法是使用Coverity的安全检查--UNINIT。UNINIT查找未初始化的堆栈变量,以及在堆上被动态分配的、可能会导致崩溃或安全问题的内存。在文件sf_bpf_filter.c的第222行中,daq-2.0.6程序包声明了一个int32类型的、名为MEM的数组。

mem的声明

图4:mem的声明

第406行在未初始化的条件下使用mem。

mem的分配

图5:mem的分配

如图中的绿色代码所示,Coverity通过循环执行所有的代码路径来仿真运行。仿真发现了:在至少一种条件下,变量MEM在初始化之前被分配给了变量A。要解决此问题,需明确地将如下第222行的数组进行全零式的初始化。

  1. int32 mem[BPF_MEMWORDS] = {0} 

2. BUFFER_SIZE

Michael Howard和David LeBlanc在《编写安全代码》一书中提到:“一个缓冲区溢出缺陷所需要的对应安全补丁的成本,有时会高达$100,000”。Coverity的安全检查--BUFFER_SIZE能够帮助开发人员找到,并修复他们C/C++代码里所包含的各种缓冲区缺陷。我们以snort-2.9.8.0程序包为例,文件encode.c的第962行初始化了PROTO_ID的各种可能变量类型,直到PROTO_MAX。PROTO_MAX是PROTO_ID枚举定义的最后一个元素:

  1. typedef enum {  
  2. PROTO_TCP  
  3. PROTO_UDP 
  4. ..............   
  5. PROTO_MAX } PROTO_ID; 

如图6所示,第960行定义了功能函数UDP_Encode。

越界读取的示例

图6:越界读取的示例

绿色的代码显示了Coverity所用到的执行路径。从NextEncoder函数返回的值被存放在PROTO_ID的下一个类型中。因此存在着如下的情况:其返回的值可能是PROTO_MAX、或22,这是枚举的最后一个元素。因为数组的索引始于0而不是1,第992行所指定的下一个位置虽然超越了数组末尾,但是会被索引到编码器数组之中。为了防止这种缓冲区溢出的可能,在它被索引到编码器数组之前,我们可以用if/else语句将第992行“卷回来”,以检查其下一个是否仍然小于PROTO_MAX。

3. USE_AFTER_FREE

定义各种变量时,一般为它们在内存中保留一个位置。当程序明确地应该释放内存时,开发人员需要确保被释放的内存不会再有被使用的可能。以不规范的方式使用内存,可能会导致不可预测的结果,和被利用的可能。

消除这些问题的一种方法是使用Coverity的安全检查--USE_AFTER_FREE。我们以netsniff-ng-0.6.0程序包为例,在文件curvetun_client.c的第304行中,声明一个指针去指向一个称为“前导(ahead)”的数据结构。如图7所示。

netsniff-ng – 前导声明

图7:netsniff-ng – 前导声明

如图8所示,第339行将前导指针分配给ai。

前导指针赋值

图8:前导指针赋值

Coverity在第358行发现前导指针已被释放。第367行的goto语句将程序的执行跳转到第311行。下一次通过在第339行的循环,指针在未被事先检查为NULL的情况下,被分配给了ai。要解决此问题,应当添加以下代码到第358行之后,将指针设置为NULL。

  1. ahead = NULL 

负责任的披露

修复了各种漏洞之后,开发人员有责任向维护人员披露其程序代码。对于像使用到GitHub的Wireshark之类的项目,各种修复项目文档(如Wireshark开发者指南,2014),被以“git push”的命令予以提交。其他的项目也会有邮件列表,或缺陷跟踪系统用于各种修复的提交。

未来的工作

在2016年1月,Coverity发布了静态分析工具的8.0版本,其中一个主要的新功能是具有分析Python代码的能力。安全洋葱包含一种被称为Scapy的数据包处理工具。Scapy正在被日益普及,尤其是在构建物联网时,可被用来分析入侵和调查各种设备。未来的项目还会去检查Scapy的静态代码分析结果。

结论

利用开源IDS加固计算机网络,需要入侵分析人员了解系统里各种软件包的安全特性。通过针对IDS的软件静态代码分析,分析人员会对开源软件所提供的安全特性更为了解。

id Software公司的联合创始人John Carmack曾说:“作为一个程序员,近年来我所做的最重要的事情就是:积极地推进了静态代码分析。”这就是这位最有名的软件开发者给大家的有关入侵分析的最佳实践。

原文标题:Using Static Analysis to Harden Open Source Intrusion Detection Systems (IDS),作者::Jeff Sass

【51CTO译稿,合作站点转载请注明原文译者和出处为51CTO.com】

【编辑推荐】

  1. 企业想要成功,如何打造下一代IT安全团队?
  2. 当今世界面临的九大安全威胁
  3. 火绒完成Pre-A轮融资 终端安全再次成为行业焦点
  4. 白山云科技合伙人丛磊:AI重新定义Web安全
  5. 颠覆传统安全方式,AI重新定义Web安全
【责任编辑:赵宁宁 TEL:(010)68476606】

点赞 0
分享:
大家都在看
猜你喜欢

读 书 +更多

软件设计师考试全真模拟试题及解析

本书是按照全国计算机技术与软件专业技术资格(水平)考试《软件设计师考试大纲》的要求,参照《软件设计师教程》及近年来考试试题编写的,...

订阅51CTO邮刊

点击这里查看样刊

订阅51CTO邮刊
× CTO训练营(深圳站)