【.com快译】入侵分析师使用网络安全监控(NSM)的原理来保护计算机系统。NSM是“对各种入侵检测和响应所涉及的识别和预警环节的收集、分析和问题升级”。NSM的核心功能包括入侵检测系统(IDS)、基于网络的IDS(NIDS)、主机入侵检测系统(HIDS)和物理入侵检测系统(PhysicalIDS)。分析师应该在部署之前评估软件包,例如IDS和HIDS。我们可以通过许多不同的方式评估给定软件包的安全级别,其中之一是使用Aberlarde方法来保护系统工程。这种方法详细评估了商业和开源软件包在软件开发生命周期(SDLC)各个阶段的安全特性。检查开源软件的优势在于可以直接访问其代码。通过这种直接访问,开发人员可以使用各种技术,例如代码检查和静态代码分析。静态代码分析(SCA)是一种在不执行软件本身的情况下发现代码问题的方法。为了实现这一点,SCA的相关工具通过使用各种可能的输入数据来模拟代码执行的不同分支可能性。SCA工具可以发现质量方面(例如COPY_PASTE_ERROR、FORWARD_NULL、INCOMPATIBLE_CAST)和安全方面(例如UNINIT、BUFFER_SIZE和USE_AFTER_FREE)方面的问题。SCA工具还可以提供特定的修复程序,开发人员可以将这些修复程序应用于源代码以降低软件的缺陷密度。它通过将组件的大小(通常是指定的代码行数)除以缺陷数来计算缺陷密度。2014年,开源软件的平均缺陷密度为每千行代码0.61个,即KLOC。相比之下,商业软件的缺陷密度为每KLOC0.76。我们有许多来自OWASP的静态分析工具可供选择。自从推出Coverity扫描服务以来,该公司在过去十年中一直备受关注。开源开发人员将他们的代码提交给Coverity的基于云的扫描服务,以供免费分析和检查。Coverity还可以在客户的本地环境中部署商业产品,以提供各种相同的分析工具。本文介绍如何在不同的部署场景中使用Coverity的静态代码分析来扫描构成SecurityOnion发行版的包。SecurityOnionSecurityOnion是由DougBurks维护的Linux发行版,包括完整的数据包捕获、NIDS、HIDS和全套分析工具。这些工具包括:netsniff-ng:用于完整数据包捕获Snort、Suricata和BroforNIDSOSSECforHIDSSguil、Squert、Snorby和ELSA:用于数据分析使用SecurityOnion与单独配置每个工具相比Distros节省时间。在开始使用此发行版进行开发之前,请按照Burks2016安装、配置和更新SecurityOnion。完成后,开发人员可以检查SecurityOnion包的源代码以查找各种安全漏洞。CoverityScanCoverity的第一个部署选项是CoverityScan。CoverityScan是一个云服务和一个免费的开源社区,注册的开源开发者可以上传他们的源代码进行分析。Coverity的静态分析引擎随后对源代码进行分析。然后,开发人员可以在生成的报告中查看各种问题,并在重新提交源代码之前按照给出的建议修复这些问题。Coverity扫描示例:在使用Wireshark进行Coverity扫描时,开发人员一般遵循四个步骤:构建、分析、提交缺陷、审查结果。在构建阶段,原始构建命令作为参数传递给Coverity的命令行:cov-build工具。cov-build命令使用--dir标志进行原始构建并将信息存储在中间目录中。我们以Wireshark为例,看下面Coverity的编译命令:$cov-build--encodingUTF-8\--dir~/cov-inter-wiresharkmake分析阶段,中间目录是手动的,或者持续集成系统(例如Travis-CI)上传到Coverity的扫描。代码分析在Coverity服务器上执行,而不是在开发人员的本地系统上执行。Coverity将自动处理提交缺陷的阶段。通过登录Coverity连接的Web界面,单个缺陷将在一行源代码中显示审查结果。Wireshark项目有许多Coverity扫描的活跃用户。自2006年以来,他们修复了数千个错误。如图1所示,软件的缺陷密度非常低,每个KLOC只有0.26个。图1:CoverityScanning:Wireshark(https://scan.coverity.com/projects/wireshark)Coverity的本地分析相对于Coverity扫描的云服务,开发者还可以选择购买Coverity的商业产品。商业产品可以在其网络上以本地模式运行。标准的Coverity部署使用两台机器来形成客户端/服务器架构。SecurityOnion一般充当本地开发主机,并将其结果以客户端的形式发送到Coverity的数据库服务器。默认情况下,SecurityOnion包作为可执行文件安装。开发者需要事先下载,然后编译分析相应的源代码。开发人员在客户端主机上执行代码分析,而不是使用Coverity扫描的服务器。存储结果的数据库在本地网络上,而不是在Coverity扫描服务器上。如图2所示,登录Coverity的Web服务器,选择合适的项目(如Wireshark),即可浏览各种结果。图2:Coverity的项目菜单如图3所示。选择项目后,您可以继续选择Coverity的菜单(三行图标)并选择“高安全风险”。图3:高安全风险过滤器此图将所有Coverity缺陷过滤到一个较小的列表中,该列表仅包含安全问题。修复安全漏洞在修复代码之前,让我们看一下如何将“不伤害规则”应用于软件,以及如何将编译器警告纳入静态分析系统。不会伤害“学习编写干净的代码并不容易”。一开始,源代码可能还很整齐,但随着时间的推移,它会变得“越来越乱”。对于一名优秀的开发人员,必须能够编写和阅读源代码。如果入侵分析师不熟悉读写代码,他们将面临艰巨的挑战。“我们可以将美国童子军的一条简单规则应用到我们的职业领域:当你离开营地时,把它打扫得比你刚到时干净。如果我们都可以签入代码,使其比编写时更干净,那么代码将是不朽的。”。“不伤害原则”有两个好处:开发人员可以提高他们的编程技能,原作者将也承认开发商是负责任的披露(responsibledisclosure)。编译器警告静态代码分析的另一个方面是编译器警告。人们往往关注代码能否编译通过,却忽略了编译器的各种警告。我们以daq-2.0.6包为例。文件daq_afpacket.c的第859行声明了一个变量rc:intrc的第866行包含:rc=send(instance->peer->fd,NULL,0,0)并且编译器警告是:daq_afpacket.c:859:25:warning:variable'rc'setbutnotused[-Wunused-but-set-variable]intrc编译器会通知开发者:调用函数send()的返回值设置了变量rc,但后续函数中没有使用rc.所以一种解决方案是:删除859行,将866行改为:(void)send(instance->peer->fd,NULL,0,0)这个修改屏蔽了编译器警告,尽量接近原来的代码。通过将send()的返回值调用分配给(void),当前代码将忽略它。另一种可能的解决方案是在第866行之后添加额外的代码来检查rc的所有返回值。这会修改程序的执行,因此需要由维护者进行审查。编译器还具有“将警告视为错误”的能力。如果开启此功能,将有利于在阶段性项目中引入编码规则。开发人员可以一次打开一个警告,一个一个地修复它们,然后在时间允许的情况下打开额外的警告。例如:在Adob??ePhotoshop中,编译器有开启“将警告视为错误”的选项,以便开发团队提高整体发现能力。如果在构建系统时不断弹出新的编译器警告,并且出现构建失败,团队可以快速发现这些错误。开启“Treatwarningsaserrors”的另一个原因是:尽量减少各种静态分析缺陷,这样你就可以在添加其他工具之前借助编译器更好地在代码层面消除那些缺陷。Coverity的各种安全检查Coverity7.7版本有70多项适用于C和C++的检查,其中18项主要针对安全问题。本节将重点介绍UNINIT、BUFFER_SIZE和USE_AFTER_FREE。1.UNINIT在ANSIC语言中,“变量的初始内容未定义”。因为语言允许定义各种变量而不进行初始化,所以C代码中经常有大量的变量没有被显式初始化。一些代码在变量声明后立即赋值,因此初始化完成。然而,有时编译器会自动为变量分配一个零值。因此,开发人员必须记住这些规则,这给软件编程留下了安全隐患。虽然C语言有解决这个问题的方法,但现在,开发人员仍然需要记住这些规则。消除这些问题的一种方法是使用Coverity的安全检查-UNINIT。UNINIT在堆上查找未初始化的堆栈变量和动态分配的内存,这些内存可能会导致崩溃或安全??问题。在文件sf_bpf_filter.c的第222行,daq-2.0.6包声明了一个名为MEM的int32类型的数组。图4:内存声明第406行使用未初始化条件下的内存。图5:mem的分配如图中绿色代码所示。Coverity通过循环执行所有代码路径来模拟运行。仿真发现,至少在一种情况下,变量MEM在初始化前被赋值给了变量A。要解决这个问题,需要在第222行显式地用全零初始化数组。int32mem[BPF_MEMWORDS]={0}2。BUFFER_SIZEMichaelHoward和DavidLeBlanc在本书《编写安全代码》中提到:“针对缓冲区溢出缺陷的相应安全补丁的成本有时可能高达100,000”。Coverity的安全检查——BUFFER_SIZE可以帮助开发人员发现并修复其C/C++代码中包含的各种缓冲区缺陷。我们以snort-2.9.8.0包为例。文件encode.c的第962行初始化了PROTO_ID的各种可能的变量类型,直到PROTO_MAX。PROTO_MAX是PROTO_ID枚举定义的最后一个元素:typedefenum{PROTO_TCPPROTO_UDP............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所示。图7:netsniff-ng-前导声明如图8所示,第339行将前导指针赋值给ai。图8:前导指针分配Coverity发现前导指针已在第358行被释放。第367行的goto语句将程序执行跳转到第311行。下一次通过第339行的循环,指针被分配给ai而没有先检查NULL。要解决此问题,应在第358行之后添加以下代码以将指针设置为NULL。ahead=NULLResponsibleDisclosure修复各种错误后,开发人员有责任向维护人员公开其程序代码。对于使用GitHub的Wireshark等项目,对项目文档(例如Wireshark开发人员指南,2014年)的各种修复是使用“gitpush”命令提交的。其他项目也有用于提交各种修复的邮件列表或错误跟踪系统。未来工作2016年1月,Coverity发布了其静态分析工具的8.0版,其中一项主要新功能是分析Python代码的能力。SecurityOnion包含一个名为Scapy的数据包处理工具。Scapy越来越受欢迎,尤其是在构建物联网时,用于分析入侵和调查各种设备。未来的项目还将检查Scapy的静态代码分析结果。结论使用开源IDS来加强计算机网络需要入侵分析人员了解系统中各种软件包的安全特性。通过对IDS的软件静态代码分析,分析人员将更好地了解开源软件提供的安全特性。idSoftware的联合创始人JohnCarmack曾说过:“作为一名程序员,我这几年做的最重要的事情就是:积极推广静态代码分析。”入侵分析的最佳实践。原标题:UsingStaticAnalysistoHardenOpenSourceIntrusionDetectionSystems(IDS),作者:JeffSass
