自主研发的静态代码安全检测是安全开发流程(SDL)
发表时间:2023-10-19 16:03:40
文章来源:炫佑科技
浏览次数:153
菏泽炫佑科技
自主研发的静态代码安全检测是安全开发流程(SDL)
源代码安全检测是安全开发过程(SDL)的重要组成部分,一般通过人工审计或自动化工具进行检测。 在大型企业中,业务线情况比较复杂,项目开发往往采用不同的编程语言和开发框架,编码风格也有很大差异。 此外,还有数亿行代码库存,并且每天都会添加大量新的代码和项目。 这些因素使得大型企业的安全实践中无法通过人工代码审计来检测。 因此,当人力紧张、工作量巨大时,*好的选择就是依靠自动化检测工具。
本文主要介绍我们自主研发的静态代码安全检测平台的总体技术原理、研发部署方案和架构、整体检测结果以及具体生产环境下的一些检测场景。
2、自动化代码漏洞挖掘技术
2.1 基于污点传播分析的自动化挖掘技术
2.1.1 检测模型
自动化代码安全检测是自动挖掘和发现源代码漏洞的安全检测。 在手动代码审计中,我们通常关注以下三点:
即用户输入可以进入代码逻辑的入口,比如PHP语言中的GPC、JAVA语言等。另外,在对框架开发的项目进行代码审计时,我们也会关注一些入口框架本身封装的方法,比如@注解。
净化操作包括两部分:系统自带的净化操作功能和用户自定义的净化操作功能。
这些清理操作函数通常可以针对某种漏洞类型在一定程度上改变传入参数的字符串,从而消除某种漏洞的威胁。 例如,函数被广泛认为用于消除 XSS 漏洞的影响,尽管在某些场景下它们仍然可以被绕过。
危险功能是触发漏洞的位置,一般根据漏洞类型进行分类讨论。 例如,SQL注入漏洞的危险PHP函数就是调用该方法来执行查询。 如果危险参数可控,就会出现SQL注入漏洞。
现在让我们将这三个元素连接在一起。 事实上,每次进行代码审计以确定可疑点是否存在漏洞(注意这里指的是常规Web安全漏洞,不包括逻辑漏洞)时,都会使用以下模型:
本章讨论如何将上述流程自动化并嵌入到互联网公司的SDL流程中。
目前,市场上有两种基于正则表达式和语义分析的检测方法。 传统基于正则表达式的代码安全扫描方案的缺点是无法很好地“理解”代码的语义,而只是将代码文件当作进行纯字符串处理。 目前比较成功的静态扫描商业产品均采用语义分析、语法分析等程序分析技术。 例如开源的Rips就是利用PHP内置的一系列API来获取token流。
${}/lib/.php 文件:
//
$ = ($这个->);
$this-> = $->(('',$this->));
未设置($);
基于对token流的分析,通过各个节点的解析器代码可以在一定程度上理解代码,比如表示抽象类、表示赋值运算符等。
除了基于令牌流进行代码分析之外,市场上越来越多的代码漏洞扫描器选择从抽象语法树级别进行代码分析。 与冗长的token流相比,语法树层面的分析更加清晰、容易。 了解,这对于平台开发者来说是个好消息。
通过更高级的语义和语法分析,我们可以从待分析的代码中获取更多的信息。 通过这些信息,可以大大提高漏洞检测的准确性。 这就是为什么目前大多数商业软件选择关注语义。 ,基于语法分析进行代码安全检测。
2.1.2 系统层面
接下来,我们将以PHP语言为例,介绍自动化白盒扫描系统所需的各个方面,并从静态分析层面给出构建自动化代码安全检测系统的思路。
我们先来有个整体的了解。 一个基于程序静态分析的自动化审计系统大致应该有以下几个部分:
(1)静态分析层
静态分析层负责“理解”代码文件,完成语义和语法层面的分析,如生成抽象语法树、生成程序控制流图等基本分析结构。 同时,对PHP语言的一些变量类型进行了分类和抽象,以供后续的数据流分析。
(2)数据流分析层
数据流分析主要负责采集代码中变量的流向自动化软件开发,同时采集变量的净化。 数据流分析是污点传播分析的基础。 它收集的信息越全面、越准确,后续的污点传播分析就会越准确。
(3)污点分析层
污点传播分析是根据数据流分析过程中获得的一系列程序信息来确定漏洞的模块。
(4)其他分析层
其他分析包括多个PHP代码文件的联合检测、基于程序上下文信息的更详细的漏洞判定分析、进程内和进程间分析等。
2.1.2.1 语义语法分析
抽象语法树(AST)按照一定的语法结构表示源代码,将一些冗余的细节抽象成树形结构。 市场上有很多语义语法分析工具,例如 ANTLR、Yacc、Lex、PHP 等。
这里我们重点关注PHP-(),作为PHP语言的语法分析工具。 使用PHP语言实现,支持节点遍历等功能。 PHP 可以使用以下命令轻松安装:
//安装:
卷曲-s|php
//安装PHP-:
./php-
具体使用请参考官方文档。
2.1.2.2 控制流分析
仅基于抽象语法树进行分析是不够的,因为抽象语法树不能很好地获取程序中流程控制语句的信息。 例如,在分析下面的示例代码时,如果不考虑程序中的分支判断,很容易出现误判:
这里进行分析的时候,遇到了对这个用户自定义函数的调用,所以我们需要在上下文中找到该方法的方法体(定义),并分析该方法的程序段。 发现它调用了安全函数后,我们可以将其添加到命令注入漏洞的安全函数中。
(2) 多文件分析
在执行多文件分析时,许多系统只是简单地依赖 use、and 等关键字来查找当前文件中包含的其他文件。 然而,在很多程序实现中,往往会使用技术,或者在统一的入口处执行文件中包含的操作。 。 因此,我们很大概率会遇到某个文件中的方法调用另一个文件中的方法,但在该文件中找不到该方法的定义语法结构的情况。
因此,在分析多个文件时,*好在分析的初始化阶段就获取所有的类定义、方法定义、通用函数定义及其路径位置自主研发的静态代码安全检测是安全开发流程(SDL),并将这些信息保存在内存中。 当我们进行后续分析时,可以直接操作内存结构,动态提取所需的方法定义。
3、企业级研发及部署计划
3.1 企业级实际场景与挑战
很多人可能认为源代码安全扫描只需要把代码拿下来扔给扫描仪,然后生成打印结果给业务线即可。 但事实上,在大型互联网公司部署并不是那么简单。 需要考虑的主要问题是:
在大公司中,可能有数千条产品线,涉及大量代码库和复杂的编程语言。 面对这种情况,本地化工具过于松散、难以管理、访问效率低下。 统一扫描平台可以提供一整套自动化接入解决方案。 统一源代码安全扫描平台可以区分多种场景下的任务类型,提供多种接入方式,更高效、自动化地提供安全扫描能力。
SDL(SDL)是微软提出的一种从安全角度指导软件开发过程的管理模型。 源代码安全扫描是SDL方法的重要组成部分。 从软件开发流程来看,源代码安全扫描处于软件开发流程的上下游,在软件上线之前需要通过安全扫描。
在我们的实践中,源代码安全扫描以插件的形式嵌入到软件开发过程中,以保护业务线代码。
这就要求平台必须具备高可用性、高响应时间和完善的用户反馈机制。
企业有一条安全红线,是企业必须遵守的*基本的安全要求。 源代码安全扫描还可以用于在系统上线前发现漏洞和非法内容,防止漏洞带上线,一定程度上保护企业业务安全。
3.2 整体架构
从分层角度来看,源代码安全扫描平台大致分为五层,每一层都有明确的职责分工。
3.2.1 接口层
接口层是平台对外输出能力的入口。 主要对接口请求进行合理性验证、权限验证、参数验证,保证请求合法、无恶意。 功能主要分为扫描界面和查询界面。 扫描接口用于接收和发起扫描任务,查询接口用于查询扫描任务的结果数据。
3.2.2 任务管理
每次扫描都是一个任务,任务管理层是整个平台的中心部分,管理所有任务的扫描状态。 主要包括三个职责:
1)状态跟踪。 任务管理跟踪并记录所有任务的扫描状态。
2)政策分配。 源码扫描平台根据实际业务场景针对不同任务实现不同的扫描策略,如根据代码变化采用缓存策略、根据代码库特点调整超时时间等。
3)超时监控。 每个任务都有一个超时时间。 当任务扫描时间超过预期值时,任务将结束并返回超时异常。
3.2.3 引擎管理层
引擎管理层是引擎调用的封装层。 在企业中,涉及多种计算机语言,不同的语言可能使用不同的源代码分析引擎。 引擎管理层向上抽象出扫描接口和报表接口。 扫描接口接收扫描数据。 下层实现具体的引擎调用策略。 报表接口获取不同引擎的扫描结果,统一生成扫描分析报告数据。
3.2.4 源代码管理
源代码管理主要关注目标源代码获取、源代码存储和源代码安全。
1)源代码获取。 源码获取主要支持两种方式。 **种是用户上传源码的方式。 这种方式需要用户自己打包源代码并上传到Web服务器。 二是与企业级代码托管平台对接,源代码管理层根据托管平台提供的安全协议拉取源代码。
2)源代码存储。 源代码存储主要包括两个方面。 一是需要扫描的源代码。 这部分源代码不会长期保存,扫描完成后一段时间内会被清除。 二是源代码存在漏洞。 这部分源代码将被永久删除。 存储以供后续分析漏洞报告。
3)源代码安全。 源代码安全扫描涉及业务线源代码的下载和分析。 对于企业来说,源代码具有*高的保密性,需要防止源代码泄露。 我们这里有两个层面的措施:**个是服务器隔离。 所有源代码操作和源代码存储都放在指定的服务器上,由源代码托管平台处理。 这种物理隔离大大降低了平台本身的管理成本。 二是所有源代码存储和传输都是加密的。 这里采用的是常用的方法,使用AES加密源代码,使用RSA加密AES密钥。
3.2.5 扫描引擎
该引擎主要采用静态代码分析技术来分析源代码中可能存在的漏洞。 详细内容请参考“自动化代码挖掘技术”章节。
3.3 SDL实践
研发工程师(RD)提交代码,进行源代码安全扫描、编译、持续集成直至部署上线。 这一系列步骤是一个完全自动化的过程,整个过程中嵌入了源代码安全扫描,这必然涉及到各个平台。 下面我们分享一下这个过程中遇到的问题。
3.3.1 接口可用性
通用平台的接口可用性要求是四个九,即SLA为99.99%。 即使是企业内部使用,也必须达到99.9%。 SLA指标很重要,因为一旦接口在一定时间内不可用,软件的持续集成受阻,就会影响正常的产品发布流程,导致产品上线出现问题。 比如,如果公司的某个产品紧急修复bug,需要上线,但在安全扫描步骤卡住了,产品线的同学可能会抓狂。
为了保证我们接口的可用性并及时发现故障,我们实施了以下策略:
3.3.2 “慢”是永恒的话题
源代码安全扫描作为软件集成发布的一个环节,在一定程度上影响着软件发布的时间。 如果安全扫描时间过长,会大大拖慢整个上线流程,安全部门本身也会承受很大的压力。
3.3.2.1 这个增量不是那个增量
有人可能会说RD大多数时候可能只修改代码库中的几个文件。 怎么会出现扫描速度慢的问题呢? 这个想法基于两个前提:**,扫描的是单个文件;第二,扫描的是单个文件。 其次,文件之间没有关联。 但实际上,正如前面漏洞分析技术中提到的,白盒代码扫描过程实际上会扫描多个相关文件。 一个文件可能会被修改,但还有许多其他文件引用该文件。 为了安全起见,因此,相关文件将被一起扫描。
因此,*初的方法是无论代码库如何变化,都使用完整扫描。 这将导致扫描速度特别“慢”。 我们经常收到业务线同学的反馈,这给运营带来了很大的压力。
3.3.2.2 增量扫描的实用方法
为了提高扫描性能,我们尝试了增量扫描策略。
大致思路是,如果我们能够分析这次变更的代码,找出当前代码库中被变更的文件所引用的文件以及引用的文件,扫描这些文件,*后将结果与全量合并。 这样可以大大减少扫描的文件数量并提高扫描速度。
具体方法是在源代码管理层中嵌入增量策略层,利用简单的源代码分析技术来获取文件的参考流程图。 通过遍历图获取增量涉及的文件。
3.3.2.3 其他优化策略
除了增量扫描之外,我们还有以下优化策略:
4. 平台检测效果
4.1 整体检测效果
开发过程中嵌入静态代码安全扫描以来,访问的代码库数量已达3000+,其中代码托管平台每天触发增量任务1700+,线上平台触发任务2500+。 根据我们的优化计划,95%的任务可以在10分钟内完成。 我们的漏洞检测规则采用手工操作和定制开发相结合的方式,漏洞准确率达到90%左右。 不同语言的漏洞分布是不同的。
目前我们的PHP检测覆盖了13类漏洞,Java语言扫描覆盖了30+类漏洞。 除了常见的Web漏洞外,它还涵盖了一些漏洞。
4.2 具体检测场景及能力 4.2.1 PHP漏洞检测
PHP漏洞检测方法详见第二章。
4.2.2 java漏洞检测
Java白盒检测需要覆盖owasp的主要Web漏洞,还需要覆盖第三方开源库的一些已知漏洞。 因此,我们针对常见漏洞和第三方开源库采取了不同的检测方法。
Java加载第三方库,这些库可能包含已知的高危漏洞,例如s2-056和-boot表达式注入漏洞。 此类由于使用旧版本组件而导致的漏洞可以通过版本检查来覆盖。 大多数版本都可以在pom.xml或build中查询。 文件,例如:
组织..
-核
2.5.16
此时可以通过检查-core版本是否在漏洞范围内来判断是否存在漏洞。 但该方法无法检测到业务线同学修改代码或添加过滤器修补漏洞,需要通过数据流分析来解决。
常见漏洞主要涵盖一些高危或中危漏洞,如sql注入、命令执行、代码执行、SSRF、任意文件上传等。对于任何一种漏洞,都需要首先获取输入点和触发点漏洞的信息以及漏洞的数据流向。 以简单的SQL注入为例:
无效(任务,),{
用户= .(“用户”);
st = conn.();
查询 = " * FROM User where ='" + user +"'";
res = st.(查询);
首先需要获取输入法::()和触发点(),然后通过数据流进行分析。 这里的数据流可以确定为:
您可以通过跟踪数据流来确定是否存在漏洞。 当然,这是*简单的模式。 为了减少实际漏洞检测中的误报,我们还需要处理以下情况:
由于Java有很多开源框架,并且大多数开源框架都有一定的安全机制,因此某些漏洞可能不符合特定框架中的常见模式。 以注入为例:
例如,如果以#{}格式引入sql语句变量,则sql语句底层直接采用预编译的形式。 这时候就不需要检测sql注入漏洞了; 如果使用${}格式,则需要按照一般sql注入流程检测。 因此,Java 中*常见的漏洞检测仍然需要适应大量使用的框架。 这时候就可以在输入点和触发点的获取上做适配了。 上例中,检测输出时,首先判断是否应用。 如果没有应用,直接检测sql语句中是否引入了${}类型变量,然后用通用的方式检测。
4.2.3/漏洞检测
和 的漏洞主要是命令执行、代码执行、sql注入、XSS和SSRF。 两者的检测思路大致相同。 首先,根据不同的框架确定输入。 主要的Web框架有-cgi(原生)、Flask、webpy,主要有-cgi(原生)、Flask、webpy等。
例如:
班级索引:
def GET(自身):
数据 = web.input()
检测时,首先需要使用正则表达式判断是否是Web应用,然后根据不同的框架获取不同的输入函数。 主要有:eval、exec、、.*、.*、.等。
简单的漏洞示例:
:
def GET(自身):
数据= web.input()
代码 = data.get('代码','')
评估(代码)
这段代码片段中,web.input()->data->code->eval可以形成一个完整的漏洞数据流,包括可控输入和漏洞触发点,因此可以确认为漏洞,从而准确检测漏洞,某些安全使用方式需要进行过滤,比如
评估(代码,{“”:无},)
这里,通过将其设置为空并设置安全白名单功能,可以更好地防止代码执行。 所以这个类型需要通过eval参数的个数来判断。
5. 总结
基于语义分析和语法分析技术构建的静态代码安全扫描器,集成和识别各种语言和框架的特征,比传统商业扫描器具有低得多的误报率和检测率。
另外,在开通上线流程中嵌入自动化静态代码安全扫描,可以在上线前有效发现代码中的安全漏洞,并**时间将源代码漏洞报告推送给业务线的开发同学进行修复。 ,把问题消灭在萌芽状态。
安全部门需要做的是不断运行安全扫描规则,处理误报反馈并增强安全能力,这可以在人工代码审计方面节省大量人力。
对于大型互联网公司来说,拥有一个可以与CI流程结合的源代码安全扫描平台是非常有必要的。 源代码安全扫描不仅可以扫描安全漏洞,还可以配合一些源代码指纹识别技术和安全开发规范来监控一些内部高风险的开源框架和不良编码习惯,可以说是一举多得。
炫佑科技专注互联网开发小程序开发-app开发-软件开发-网站制作等