原文链接:https://mp.weixin.qq.com/s/d9RzCFkYrW27m1_LkeA2rw
源代码安全检测是安全开发流程(SDL)中非常重要的一部分,在58集团的CI/CD流程中每天有数千次量级的构建及发布,白盒检测的自动化能力显得极为重要。企业级的白盒代码审计系统就不仅仅面临漏洞发现的需求,也需要适应企业CI/CD流程。由于58集团大部分业务使用自研的Java框架,本系列文章会重点介绍我们在Java白盒能力建设过程中的实践。
本文主要介绍58集团 Java白盒能力建设中的技术选型过程,分享我们对业内常见的商业、开源产品进行分析的情况。
静态代码分析是指在不实际执行程序的情况下,对代码语义和行为进行分析,由此找出程序中由于错误的编码导致异常的程序语义或未定义的行为。通俗的说,静态代码分析就是在代码编写的同时就能找出代码的编码错误。你不需要等待所有代码编写完毕,也不需要构建运行环境,编写测试用例。它能在软件开发流程早期就发现代码中的各种问题,从而提高开发效率和软件质量。
静态AST(SAST)技术通常在编程和/或测试软件生命周期(SLC)阶段分析应用程序的源代码,字节代码或二进制代码以查找安全漏洞。
我们出于自身需求,对常见的开源方案以及部分商业方案进行了一些选型统计
产品 | 是否开源 | 是否支Java AST | 是否支持跨文件 | 定制化需求难易度 | 是否Web项目友好 | 安全规则编写难度 | 是否支持代码质量检查 | 支持语言 | 可扩展性 | 是否侵入项目 | 是否支持Jar包扫描 | 是否支持移动端 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
Coverity | 否 | 是 | 是 | 极难,需要厂商支持 | 是 | 相对困难 | 支持 | 常见语言都支持 | 低,需厂商支持 | 否 | 是 | 否 |
SonarQube | 是 | 是 | 否 | 相对简单 | 是 | 相对简单 | 支持 | 常见语言都支持 | 高 | 否 | 否 | 否 |
FlowDroid | 是 | 是 | 是 | 相对困难 | 否 | 相对困难 | 支持 | Android/Java | 中 | 否 | 是 | Android |
ErrorProne | 是 | 是 | 是 | 相对困难 | 否 | 相对困难 | 支持 | Android/java | 中 | 是 | 是 | Android |
Infer | 是 | 是 | 是 | 相对困难 | 否 | 相对困难 | 支持 | Android/java | 中 | 是 | 是 | Android |
Soot | 是 | 是 | 是 | 相对困难 | 否 | 相对困难 | 支持 | Android/java | 中 | 否 | 是 | Android |
PMD | 是 | 是 | 否 | 相对简单 | 是 | 相对简单 | 支持 | java | 高 | 否 | 否 | 否 |
CodeQL | 半开源 | 是 | 是 | 中等 | 是 | 相对简单 | 支持 | 除php外常见语言 | 高 | 否 | 是 | 否 |
Coverity、Fortify、CheckMarx 作为白盒静态扫描领域的领头产品,拥有极其深厚的技术积累以及专业的产品技术团队。其产品能力都为业界翘楚。笔者曾经和Coverity的售前及售后团队有过一定的交流,可以总结以上商业产品的优点及缺点
1、Converity的C/C++安全扫描依赖本地编译环境,需要研发使用Converity下发的扫描脚本进行编译扫描,但是扫描脚本对MacOS的版本适配一般都会delay 2~3个月,这就会造成MacOS一更新,对C/C++的安全扫描业务就会中断。Convertiy也未提供编译机的方案进行统一编译(有很多原因,比如编译参数、平台不一致难以统一编译)
2、Converity对代码的安全扫描并不只上报安全漏洞,代码的质量问题也会上报。但是Converity并未明显区分代码质量问题和安全漏洞,每个项目数千计数的代码质量问题和安全漏洞难以修复落地
SonarQube、FindBugs、Chechstyle都是一些老牌开源静态代码扫描工具,但是这些工具都更偏向代码质量检查而非安全性检查。我们可以总结这些老牌开源产品的优点及缺点
FlowDroid是一款使用Java实现的针对Android的静态污点分析框架,发表于PLDI'2014,截止撰文时间在Google Scholar上显示已有1200+的引用,目前为Android静态污点分析的主流框架,代码开源并提供于GitHub。
Github仓库:https://github.com/secure-software-engineering/FlowDroid
命令行使用
github下载jar包soot-infoflow-cmd-jar-with-dependencies.jar;
命令行调用分析
java -jar soot-infoflow-cmd-jar-with-dependencies.jar \ -al 500 -mc 500 -md 500 -a <待分析的APK文件路径> \ -p <Android SDK平台目录路径> \ -s <污染源和Sink点的定义文件>
使用Maven构建FlowDroid
EXPORT ANDROID_JARS=<Android JAR folder> EXPORT DROIDBENCH=<DroidBench folder> mvn install
针对Android的开源框架,相比于跨语言的工具复杂性相对较低
工具封装仅支持apk的分析
BenchMark强依赖于安卓相关的方法,用例也基于安卓的场景设计。安全相关的规则需要自行编写用例
由Google出品,使用ErrorProne接管compiler,在代码编译时进行检查,并抛出错误中断执行。常用于静态的Java和Android bug分析。
github仓库:https://github.com/google/error-prone
支持Bazel
、Maven
、Gradle
、Ant
、IDE扩展、命令行 等不同安装方式,以Maven为例,build时依赖maven-compiler-plugin
扩展,且需要关注JDK版本:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.0</version> <configuration> <source>1.8</source> <target>1.8</target> <encoding>UTF-8</encoding> <fork>true</fork> <compilerArgs combine.children="append"> <arg>-XDcompilePolicy=simple</arg> <arg>-Xplugin:ErrorProne -Xep:DeadException:WARN -Xep:GuardedBy:OFF</arg> <arg>-J-Xbootclasspath/p:${settings.localRepository}/com/google/errorprone/javac/9+181-r4173-1/javac-9+181-r4173-1.jar</arg> </compilerArgs> <annotationProcessorPaths> <path> <groupId>com.google.errorprone</groupId> <artifactId>error_prone_core</artifactId> <version>2.4.0</version> </path> </annotationProcessorPaths> </configuration> </plugin>
bootclasspath
参数的javac版本依据实际环境需要调整。
编译执行
mvn clean && mvn compile -e
如果扫描后未发现缺陷点,则构建通过:
如果发现缺陷点,将抛出CompilationFailureException
异常,且导致mvn构建失败:
需要手动侵入Maven工程项目的POM文件,且需要关注及适配编译器和版本等细节;
编译阶段扫描缺陷点,没有友好的导出方案,需要从compile failed异常中捞取信息及整理;
无法拿到完整的AST信息;
Infer 是 Facebook 开源的静态程序分析工具,用于在发布移动应用之前对代码进行分析,找出潜在的问题。目前 Facebook 使用该工具来分析 Facebook 的 App,包括 Android 、iOS、Facebook Messenger 和 Instagram 等等
官方文档:https://fbinfer.com/docs/getting-started/
Github仓库:https://github.com/facebook/infer
安装较为简单,支持MacOS
和Linux
,以及Docker Image
部署:https://fbinfer.com/docs/getting-started
支持多语言,Java的Maven项目有专门支持:
ant
buck
cc
gradle
java
javac
make
mvn
ndk-build
xcodebuild
扫描调研
# 扫描前需先清理 mvn clean && infer -- mvn package
结果文件默认输出在项目的infer-out/
目录下,分析运行时间与项目相关(理想时间预计在10~20min)。
官方最新版本放弃了对AL(AST Language)的维护,并在后续版本中会删除AL功能:
https://fbinfer.com/docs/checker-linters
*\DEPRECATED*** On end-of-life support, may be removed in the future.
对于Github中用户提起的弃用原因,目前官方暂无正面回应:
https://github.com/facebook/infer/issues/1325
soot是java优化框架,提供4种中间代码来分析
和转换
字节码:
Baf:精简的字节码表示,操作简单
Jimple:适用于优化的3-address中间表示
Shimple:Jimple的SSA变体
Grimple:适用于反编译和代码检查的Jimple汇总版本。
github仓库:https://github.com/soot-oss/soot
支持分析的格式包含Java字节码(<=JDK9+)、Java源码(<=JDK7)、Android字节码、Jimple中间表示、Jasmin低级中间表示
分析功能支持CFG控制流图绘制、指针分析、Def/use chains、数据流分析、结合FlowDroid的污染分析
安装
在Maven Central
中下载所需版本的包:
https://repo.maven.apache.org/maven2/org/soot-oss/soot/
或者从java Doc的下载地址:
https://soot-build.cs.uni-paderborn.de/public/origin/master/soot/soot-master/
使用
# 变量声明 # soot的jar包路径 export SOOT_PATH=/path/to/soot/soot-4.2.1-jar-with-dependencies.jar # soot分析时所需扫描的依赖类文件路径,多个按":"分割 # soot-class-path 只能精确到文件,不支持目录 export SOOT_CLASS_PATH=/path1/jar1.jar:/path2/jar2.jar # 分析target/classes目录下的单个入口文件 java -cp $SOOT_PATH soot.Main -pp \ -cp .:$JAVA_HOME/jre/lib/rt.jar:$SOOT_CLASS_PATH org.packageName.MainClassName # 在字节码目录分析单个入口文件 java -cp $SOOT_PATH soot.Main -pp \ -cp .:$JAVA_HOME/jre/lib/rt.jar:$SOOT_CLASS_PATH ClassName # 分析当前目录 java -cp $SOOT_PATH soot.Main -pp \ -cp .:$JAVA_HOME/jre/lib/rt.jar:$SOOT_CLASS_PATH -process-dir . # 分析jar包 java -cp $SOOT_PATH soot.Main -pp \ -cp .:$JAVA_HOME/jre/lib/rt.jar:$SOOT_CLASS_PATH -process-dir /path/to/jarFileName.jar # 绘制入口文件的控制流图 java -cp $SOOT_PATH soot.tools.CFGViewer -pp \ --soot-class-path .:$JAVA_HOME/jre/lib/rt.jar:$SOOT_CLASS_PATH \ --graph=BriefBlockGraph -d ./sootOutputGraphImg org.packageName.MainClassName # 绘制整个目录的控制流图 java -cp $SOOT_PATH soot.tools.CFGViewer -pp \ --soot-class-path .:$JAVA_HOME/jre/lib/rt.jar:$SOOT_CLASS_PATH \ --graph=BriefBlockGraph -process-dir .
详细可参考https://www.sable.mcgill.ca/soot/tutorial/usage/
主要用到的几个参数:
-d
输出目录路径,为指定使用默认路径为终端当前所在目录下的./sootOutput
文件夹-f
输出类型,默认输出.class文件-dump-cfg phaseName
导出控制流图phaseName
可指定导出阶段,如-dump-cfg jb -dump-cfg bb.lso 可导出 jb 和 bb.lso阶段的构建CFG。-dump-cfg ALL则导出所有阶段的PMD 是一个开源的静态代码分析工具。它用于分析一些常见的编程缺陷(未使用的变量、空捕获块、不必要的对象创建等)。
支持的语言:
Github仓库:https://github.com/pmd/pmd
安装运行:
./run.sh pmd \
-d /path/to/待分析工程目录
-R /path/to/规则集文件.xml
-f text
text
,支持如xml
、json
、html
等。详见: https://pmd.github.io/latest/pmd_userdocs_report_formats.html <?xml version="1.0"?> <ruleset name="Custom Rules" xmlns="http://pmd.sourceforge.net/ruleset/2.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd"> <description> My custom rules </description> <!-- 规则存放处 --> <!-- 这里使用了内置的java errorprone规则,检查空catch块 --> <rule ref="category/java/errorprone.xml/EmptyCatchBlock" /> </ruleset>
规则分类
所有 PMD 内置规则都按照以下八个类别进行分类
Best Practices 最佳实践: 这些规则强制执行公认的最佳做法
Code Style 代码风格: 这些规则强制执行特定的编码风格
Design 设计: 这些规则帮助发现设计问题
Documentation 文档: 这些规则与代码文档有关
Error Prone 易出错: 用于检测破坏、极度混乱或容易出现运行时错误的构造的规则
Multithreading 多线程: 这些规则在处理多个执行线程时标记问题
Performance 工作表现: 这些规则标记未达到最佳标准的代码
Security 安全: 标记潜在安全缺陷的规则
详见Java的内置规则清单:https://pmd.github.io/latest/pmd_rules_java.html
Security内置规则
Security相关的只有两个:
<rule ref="category/java/security.xml/HardCodedCryptoKey" />
<rule ref="category/java/security.xml/InsecureCryptoIv" />
CodeQL是 Github 安全实验室推出的一款静态代码分析引擎,其利用QL语言对代码、执行流程等进行“查询”,以此实现对代码的安全性白盒审计,进行漏洞挖掘
CodeQL为白盒漏洞扫描提供了一些新的思路
在调研了大量的开源SAST的产品方案后,我们发现CodeQL作为Github安全实验室的产品,基本上代表了开源产品的在SAST领域的最佳实践(LGTM平台化及平台里AI训练场景暂不讨论),但由于官方申明不支持企业集成到CI/CD流程,于是我们选择参照CodeQL的设计思路,使用Spoon(Java AST解析器)加上自研跨文件串联能力作为扫描引擎的自研方案。后面的文章我们将详细分析SAST的技术原理以及58基础安全团队学习CodeQL的过程及教程输出。
扫码关注58安全应急响应中心官方微信公众号,第一时间获得最新消息