系列 | 58集团白盒代码审计系统建设实践1:技术选型

百家 作者:58安全应急响应中心 2021-03-19 18:25:34
背 景

源代码安全检测是安全开发流程(SDL)中非常重要的一部分,在58集团的CI/CD流程中每天有数千次量级的构建及发布,白盒检测的自动化能力显得极为重要。企业级的白盒代码审计系统就不仅仅面临漏洞发现的需求,也需要适应企业CI/CD流程。由于58集团大部分业务使用自研的Java框架,本系列文章会重点介绍我们在Java白盒能力建设过程中的实践。

本文是58白盒扫描建设之路系列文章第一篇,主要介绍58集团 Java白盒能力建设中的技术选型过程,分享我们对业内常见的商业、开源产品进行分析的情况。



一、SAST简介


静态代码分析是指在不实际执行程序的情况下,对代码语义和行为进行分析,由此找出程序中由于错误的编码导致异常的程序语义或未定义的行为。通俗的说,静态代码分析就是在代码编写的同时就能找出代码的编码错误。你不需要等待所有代码编写完毕,也不需要构建运行环境,编写测试用例。它能在软件开发流程早期就发现代码中的各种问题,从而提高开发效率和软件质量。

静态AST(SAST)技术通常在编程和/或测试软件生命周期(SLC)阶段分析应用程序的源代码,字节代码或二进制代码以查找安全漏洞。



二、业内知名代码审计产品



01 知名商业产品



02 知名开源项目





三、技术选型思考


01 技术选型结果统计

我们出于自身需求,对常见的开源方案以及部分商业方案进行了一些选型统计:

02 商业产品分析

Coverity、Fortify、CheckMarx 作为白盒静态扫描领域的领头产品,拥有极其深厚的技术积累以及专业的产品技术团队。其产品能力都为业界翘楚。笔者曾经和Coverity的售前及售后团队有过一定的交流,可以总结以上商业产品的优点及缺点:

优 点:

  • 深厚的技术积累,产品能力强大,在SAST领域内少有不支持扫描的漏洞类型;

  • 售后团队专业,能较为理解用户需求。

缺 点:

  • 定制化需求支持困难,引擎对用户不透明,需求提交给厂商相应时长为 Month ++;

  • 规则学习成本高,规则学习文档不完善,自定义规则困难;

  • 厂商以最大并发量授权license,弹性扩容能力差,存在成本浪费;

  • 漏洞模型难以适配每个用户自己内部的漏洞模型,难以准确处理误报、漏洞修复复查等业务需求;

  • 融入企业自身的CI/CD流程困难,数据模型需要企业自己转换。

实际案例:

1、Converity的C/C++安全扫描依赖本地编译环境,需要研发使用Converity下发的扫描脚本进行编译扫描,但是扫描脚本对MacOS的版本适配一般都会delay 2~3个月,这就会造成MacOS一更新,对C/C++的安全扫描业务就会中断。Convertiy也未提供编译机的方案进行统一编译(有很多原因,比如编译参数、平台不一致难以统一编译);

2、Converity对代码的安全扫描并不只上报安全漏洞,代码的质量问题也会上报。但是Converity并未明显区分代码质量问题和安全漏洞,每个项目数千计数的代码质量问题和安全漏洞难以修复落地。

03 开源产品分析

SonarQube、FindBugs、Chechstyle都是一些老牌开源静态代码扫描工具,但是这些工具都更偏向代码质量检查而非安全性检查。我们可以总结这些老牌开源产品的优点及缺点:

优 点:

  • 源代码开源;

  • 适配Jenkins等持续集成软件。

缺 点:

  • 没有跨文件AST能力,无法分析跨文件数据流和控制流;

  • 漏洞匹配模式导致误报非常高,难以落地运营。


04 其他开源产品分析


① FlowDroid


现状分析

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强依赖于安卓相关的方法,用例也基于安卓的场景设计。安全相关的规则需要自行编写用例。


② ErrorProne


现状分析

由Google出品,使用ErrorProne接管compiler,在代码编译时进行检查,并抛出错误中断执行,常用于静态的Java和Android bug分析。

产品概要

官方文档:http://errorprone.info/

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


现状分析

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


现状分析

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文件

    • J, jimple ,也是我们需要关注的IR中间表示,它位于Java源码和字节码之间,是基于类型的3地址格式;

    • X, xml;

    • c, class 经soot分析后重新生成的字节码;

    • t, template ,反编译还原的.java文件,也是基于Jimple生成的。

  • -dump-cfg phaseName 导出控制流图

    • phaseName可指定导出阶段,如-dump-cfg  jb -dump-cfg bb.lso 可导出 jb 和 bb.lso阶段的构建CFG,-dump-cfg ALL则导出所有阶段的;

    • 导出控制流图会触发soot的bug抛NPE异常,目前可以使用CFGViewer来导出方法签名粒度的控制流图。

优劣势

  • 优势

    • 支持Java字节码和源码的分析;

    • 支持Android代码的分析;

    • 可绘制可视化的控制流图。

  • 劣势

    • soot的前端编译器已经过时,官方建议仅用作编译后文件的分析而不是源码分析;

    • 当前维护版本(4.2.1)依赖高版本JDK(JDK11),且对JDK9+的字节码分析也存在bug,而旧版soot对JDK7及以下的源码分析更是缺乏维护;

    • 控制流图绘制不支持跨文件串联,而是依据包结构对每个文件生成对应的控制流图。


⑤ PMD


现状分析

PMD 是一个开源的静态代码分析工具。它用于分析一些常见的编程缺陷(未使用的变量、空捕获块、不必要的对象创建等)。

支持的语言:

  • Java
  • JavaScript
  • Apex      和 Visualforce
  • Modelica
  • PLSQL
  • Apache      Velocity
  • XML
  • XSL
  • Scala

产品概要

官方文档:https://pmd.github.io/

Github仓库:https://github.com/pmd/pmd

技术分析及使用

安装运行:

  • 下载bin压缩包:https://github.com/pmd/pmd/releases

  • 执行命令:

./run.sh pmd \-d /path/to/待分析工程目录-R /path/to/规则集文件.xml-f text
  • -f取值:默认 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" />

优劣势

  • 优势

    • 可分析多种语言的源码;

    • 不需要参与代码编译;

  • 劣势

    • 不支持分析编译后文件;

    • 内置安全规则较为薄弱,SAST所需规则均需要自定义编写;


04 白盒静态扫描战斗机——CodeQL

简 介

CodeQL是 Github 安全实验室推出的一款静态代码分析引擎,其利用QL语言对代码、执行流程等进行“查询”,以此实现对代码的安全性白盒审计,进行漏洞挖掘。

整体流程

  • 通过适配各个语言的AST解析器,并将代码的AST解析结果按照预设好的数据模型将代码AST数据及其依赖关系存储到CodeDB里;

  • 通过QL语言定义污点追踪漏洞模型;

  • 执行QL时通过高效的搜索算法对CodeDB的AST元数据进行高效查询,从而在代码中搜索出漏洞结果。

优 点

  • 以CodeDB的模式存储源代码数据,并提供高效的搜索算法及QL语言对漏洞进行查询,支持数据流与控制流,使用者无需考虑跨文件串联的算法难度;

  • 支持除PHP以外的常见语言类型;

  • QL规则开源且正在迭代,有很非常强的可扩展性及支持定制化规则能力;

  • QL规则有相应的文档学习,无需依赖厂商支持;

  • 可以深入Jar包进行漏洞扫描。

缺 点

  • AST分析引擎不开源,无法针对AST的元数据进行调整修改,并且官方申明只用于研究用途,不允许企业集成至CI/CD流程;

  • 不支持运行时动态绑定的重载方法分析(其他SAST产品的也不支持);

  • 不支持Resource文件的扫描,不做二次开发的情况下无法支持类似Mybatis XML配置的场景;

  • 不支持软件成分分析,无法结合软件版本进行漏洞判断。

评 价

CodeQL为白盒漏洞扫描提供了一些新的思路:

  • 通过格式化AST数据将它们进行结构化存储,再通过高效率的有向图搜索/裁剪算法支持对这些元数据进行基本查询;

  • 通过对不同语言的适配,把一些常用的查询封装成QL语言,对AST数据进行一种类SQL的查询;

  • 通过QL语言定义漏洞查询三元组<sources,sinks,sanitizers>(即污点追踪)可进行漏洞查询建模,并且由于查询可以直接搜索AST元数据,可以对DataFlow以及ControlFlow进行更细致的判断,以减少误报、漏报;

  • 通过悬赏开源社区收录QL规则,保障了规则的迭代更新;

  • 通过CodeQL的开源规则以及Github庞大的开源代码及迭代数据,实现打标能力为后续LGTM平台的神经网络学习提供学习样本。



四、选型结论


在调研了大量的开源SAST的产品方案后,我们发现CodeQL作为Github安全实验室的产品,基本上代表了开源产品的在SAST领域的最佳实践(LGTM平台化及平台里AI训练场景暂不讨论),但由于官方申明不支持企业集成到CI/CD流程,于是我们选择参照CodeQL的设计思路,使用Spoon(Java AST解析器)加上自研跨文件串联能力作为扫描引擎的自研方案。

后续的文章我们将详细分析SAST的技术原理以及58基础安全团队学习CodeQL的过程及教程输出。





58招聘,就等你来!



投递邮箱:src@58.com

更多岗位:https://security.58.com/contact/




高级java研发工程师

北京

岗位职责


1、参与完成中小型项目的系统分析、设计,并主导完成详细的设计,并负责核心业务功能与底层基础功能的功能设计、代码实现与单元测试;

2、能够在团队中完成code review的任务,确保相关代码的有效性和正确性,并能够通过code review提供相关性能以及稳定性的建议;

3、参与建设通用、灵活、智能的支撑平台的讨论与设计,支撑上层多场景的复杂业务。

工作内容


1、负责Java工程项目包括但不限于白盒扫描系统、Rasp动态防护系统的设计与实施,并完成基础核心系统研发工作;

2、参与业务规则梳理,与业务方一起设计并讨论业务场景实现;

3、对现有系统的不足进行分析,找到目前系统的瓶颈,进行重构优化和改进,提高系统性能;

4、参与重点项目的设计方案支持与评审,难点攻关。


任职要求


1、本科或以上学历,计算机软件或相关专业,3年以上Java开发经验;

2、熟悉Java/JEE, 基础扎实,熟练掌握常用Java技术框架,能编写高质量简洁清晰的代码;

3、对于Java基础技术体系(包括JVM、类装载机制、多线程并发、IO、网络)有一定的掌握和应用经验;

4、良好的面向对象设计理解,熟悉面向对象设计原则,具备熟练的领域建模技能和一定的抽象思维能力;

5、具有比较强的问题分析和处理能力,有比较优秀的动手能力,热衷技术,精益求精,有一定的技术癖;

6、熟悉底层中间件、分布式技术(包括缓存、消息系统、热部署、JMX等);

7、对于JVM虚拟机、字节码处理、静态代码分析有过实际项目经验者优先。


成长建议


1、熟悉各分布式中件间使用场景;

2、独立完成业务梳理与架构设计;

3、通过阅读技术书籍与技术博客充实技术栈




高级安全工程师(DevSecOps方向)

北京

岗位职责


1、参与公司DevSecOps制度、流程、平台制定并推动落地;

2、参与公司产品的安全需求评审、安全架构评审、代码审计、安全测试等工作;

3、参与公司DevSecOps自动化工作的建设及运营,包括但不限于自动化的黑盒测试、白盒测试规则的开发及维护;

4、推动DevSecOps建设,对研发人员进行安全技术和意识培训;

任职要求


具备SDL实践经验,主导或参与过黑白盒、Rasp等安全产品的建设、有自动化白盒代码审计的经验;




高级安全研发工程师(Python)

北京

岗位职责


1、负责58安全平台部,漏洞扫描、入侵检测等安全产品的设计与研发;

2、 参与部门内部基础安全产品的平台化系统设计和实现;


任职要求


1、统招本科及以上学历,计算机等相关专业。

2、精通Python编程语言。

3、熟悉Django、celery等框架与组件。

4、了解python并发编程模型,深入理解进程、线程、协程等概念。

5、熟悉常用算法和数据结构,对系统性能优化有一定经验。

6、熟悉MySQL、Redis、zookeeper、kafka等分布式中间件。

7、熟悉Flink、spark、Hadoop等大数据开发平台优先。

8、熟悉网络编程,对计算机网络通讯有深入理解。

9、熟悉linux等系统环境,可以快速定位和解决线上各种系统问题。

10、具有黑盒扫描器研发经验的优先。

11、善于学习和运用新知识,具有良好的分析和解决问题能力。

12、具有良好的团队合作精神和积极主动的沟通意识。




高级安全研发工程师(Golang)

北京

岗位职责


1、负责58安全平台部,主机入侵检测等安全产品的设计与研发;

2、参与部门内部基础安全产品的平台化系统设计和实现;


任职要求


1、统招本科及以上学历,计算机等相关专业。

2、精通Golang编程语言。

3、有扎实的编程能力和代码品位,良好的数据结构和算法基础。

4、深入理解Linux及其原理,熟悉网络编程,对计算机网络有深入理解。

5、熟悉常用存储、缓存、消息队列等基础中间件产品,并了解基本原理。

6、熟悉互联网行业主流分布式系统设计,了解分布式存储/缓存/数据库等基础系统的核心架构及原理。

7、了解Linux内核,有eBPF开发、应用经验者优先。

8、熟悉Python开发和Flink、Spark、Hadoop等大数据开发平台者优先。

9、有安全产品(HIDS、WAF、扫描器等)研发经验者优先。

10、善于学习和运用新知识,具有良好的分析和解决问题能力。

11、具有良好的团队合作精神和积极主动的沟通意识。



扫码关注我们

58安全应急响应中心希望与业界同仁共同建立诚信、安全、可靠的安全平台。同时通过白帽英雄们反馈的58集团漏洞和威胁情报,不断提升58产品和业务的安全。



点击查看更多岗位

关注公众号:拾黑(shiheibook)了解更多

[广告]赞助链接:

四季很好,只要有你,文娱排行榜:https://www.yaopaiming.com/
让资讯触达的更精准有趣:https://www.0xu.cn/

公众号 关注网络尖刀微信公众号
随时掌握互联网精彩
赞助链接