app漏洞扫描工具有哪些,app漏洞挖掘教程分享
目前Android应用代码漏洞扫描工具种类繁多,效果良莠不齐,这些工具有一个共同的特点,都是在应用打包完成后对应用进行解包扫描。这种扫描有非常明显的缺点,扫描周期较长,不能向开发者实时反馈代码中存在的安全问题,并且对于问题代码的定位需要手动搜索匹配源码,这样就更不利于开发者对问题代码进行及时的修改。Code Arbiter正是为解决上述两个问题而开发的,专门对Android Studio中的源码进行安全扫描。
1 背景介绍
为实现对Android Studio中的源码进行扫描,最方便的方式便是将扫描工具以IDE插件的形式进行工作。此时一个很自然的想法便是从头构建一个Android Studio插件,但是进行仔细的评估后会发现,这样做难度并不小:
工作量大,许多知识需要学习,如IDE开放API接口、插件UI构建等,同时许多底层模块需要从头构建;插件的稳定性、检测问题的准确性上都不一定能够达到已有开源工具的效果。
因此我们转而考虑在已有漏洞检测插件的基础上进行扩展,以满足需求。经过调研,最终入围的两款检测插件是PMD和FindBugs,其中PMD是对Java源码进行扫描,而FindBugs则是对Java源码编译后的class文件进行扫描。考虑到可扩展性及检测的准确性,最终选定了FindBugs。FindBugs是一个静态分析工具,它检查类或者JAR文件,将字节码与一组缺陷模式进行对比来发现可能的问题,可以以独立的JAR包形式运行,也可以作为集成开发工具的插件形式存在。
扩展优化
那么,怎么扩展FindBugs呢?调研发现FindBugs插件具有着极强的可扩展性,只需要将扩展的JAR包导入FindBugs插件,重启,即可完成相关功能的扩展。安装JAR包示意图如下所示。
下面的问题是如何构建可安装的JAR包。继续调研,发现FindBugs有一款专门对安全问题进行检测的扩展插件Find Security Bugs,该插件主要用于对Web安全问题进行检测,也有极少对Android相关安全问题的检测规则。考虑以下几个原因,需要对该插件的源码进行重构。
对Android安全问题的检测太少,只包含外部文件使用、Webview、Broadcast使用等寥寥几项;检测的细粒度上考虑不够完全,会造成大量的误报,无法满足检测精度的要求;检测问题的上报只支持英文模式,且问题展示的逻辑性不够严谨,不便于开发者进行问题排查。
基于以上三个原因,我们需要对Find Security Bugs的源码进行重写、优化,通过增加检测项来检测尽可能多的安全问题,通过优化检测规则来减少检测的误报,问题展示使用中文进行描述,同时优化问题描述的逻辑性,使得开发者能够更易理解并修改相关问题,至此插件实现及优化的方案确定。
2 工具实现介绍
FindBugs检测的是class文件,因此当待检测的源码未生成编译文件时,FindBugs会先将源码编译生成.class文件,然后对这个class文件进行分析。FindBugs会完成对class文件的自动建模,在此模型的基础上对代码进行分析。按照在实际编写检测代码过程中的总结,把检测的实现方式分成四种方式,下面分别进行介绍。
2.1 逐行检查
逐行检查主要是针对代码中使用的一些不安全方法或参数进行检测,其实现方式是重写sawOpcode()方法,下面以Android中使用外部存储问题作为示例进行讲解。
Android中获取外部存储文件夹地址的方法主要包括下面这些方法:
getExternalCacheDir()
检测的方式便是,如果发现存在该方法的调用,则作为一个问题进行上报,实现完整代码如下所示:
public class ExternalFileAccessDetector extends OpcodeStackDetector { private static final String ANDROID_EXTERNAL_FILE_ACCESS_TYPE = "ANDROID_EXTERNAL_FILE_ACCESS"; private BugReporter bugReporter; public ExternalFileAccessDetector(BugReporter bugReporter) { this.bugReporter = bugReporter;
该类的实现是继承OpcodeStackDetector类,是FindBugs中的一个抽象类,封装了对于获取代码特定参数的方法调用。sawOpcode方法参数可以理解为待检测代码行的行号,通过printOpCode(seen)可以打印该代码行的具体内容。Constants.INVOKEVIRTUAL表示该行调用类的实例方法,Constants.INVOKESTATIC表示调用类的静态方法。getNameConstantOperand方法表示获取被调用方法的名称,getClassConstantOperand方法表示获取调用类的名称,getSigConstantOperand方法表示获取方法的所有参数。bugReporter.reportBug用于上报检测到的漏洞信息,其中BugInstance的三个参数分别表示:检测器、漏洞类型、漏洞等级,其中漏洞等级分为五个级别,如下表所示:
对原始class文件进行分析存在的缺陷是无法定位具体的代码行,那么在进行问题上报时无法将问题定位到代码行,因此第一步需要在原有模型的基础上对所有包含Intent获取参数的方法的位置存储到一个Map结构中,方便后面对方法的定位,代码实现如下所示,获取方法所在的行,然后以方法名作为Key值,以代码行相关信息作为Value值,存储到Map中。
private Map<String, List<Location>> get_line_location(Method m, ClassContext classContext){
之后获取Exception包裹的范围,FindBugs中包含对Exception的建模,因此能够通过其模型能够直接获取其范围并存储到一个列表中,代码如下所示,其中exceptionTable[i].getStartPC用于获取try catch 的起始代码行,exceptionTable[i].getEndPC用于获取try catch 的结束代码行。
public int[] getExceptionScope(){ try {
在对代码进行逐行检查时,因为使用的是最原始class文件形式,因此需要限定其遍历的范围,限定的方式是通过代码的行号,即上图中每行代码的第一个数值。首先需要获取代码总行数的大小,获取的方式便是解析FindBugs建模后的第一行代码,找到关键词code-length后面的数值,即为代码的行数,解析代码如下所示:
public int get_Code_Length(String firstLineCode){ try{
最后对代码进行逐行遍历,遍历中为防止try catch块被遍历到,使用行号来限制遍历的范围。检测代码行是否包含通过Intent获取参数,及该行是否被try catch 包裹,如果上述两个条件均被触发,那么就作为一个问题进行上报。示例代码如下,其中get_code_line_index方法用于获取代码的行号,获取的方式是截取代码行的首字符的数值,以确定是否在代码包裹的范围内。
private void analyzeMethod(JavaClass javaClass, Method m, ClassContext classContext) throws CFGBuilderException {
3 注册打包
上面详细叙述了如何构造自己的问题检测代码,完成检测方法的书写后,下一步就是在配置文件中对检测方法进行注册,才能使检测代码运转起来。
需要在两个文件中进行注册,第一个是findbugs.xml,注册示例如下:
<Detector class="com.h3xstream.findsecbugs.android.LocalDenialOfServiceDetector" reports="LOCAL_DENIAL_SERVICE"/>
其中Detector用于注册该检测方法的位置及其唯一标识,BugPattern用于对检测出的问题进行归类,方便展示,如此处归类到”Android安全问题”中,那么在生成报告的时候问题也将被归类到”Android安全问题”中。
第二个是messages.xml注册,注册示例如下,该注册主要是对该问题进行说明,包括问题的危害及修复方法。
<Detector class="com.h3xstream.findsecbugs.android.LocalDenialOfServiceDetector"><Details>Local Denial of Service.</Details></Detector><BugPattern type="LOCAL_DENIAL_SERVICE"><ShortDescription>本地拒绝服务</ShortDescription><LongDescription>通过Intent接收的参数未进行异常捕获,导致出现异常使得应用崩溃</LongDescription><Details><![CDATA[ <p> <b>危害:</b><br/> <pre> 应用崩溃无法使用,影响用户体验; 被竞争对手利用,进行点对点攻击。 </pre> </p> <p> <b>错误代码:</b><br/> <pre> bundle.getString(""); //未try/catch intent.getStringExtra(""); //未try/catch </pre> </p> <p> <b>解决方案:</b><br/> <pre> 对通过Intent接收的参数处理时,进行严格的异常捕获。 try { bundle.getString(""); intent.getStringExtra(""); }catch (Exception e){} </pre> </p>]]></Details></BugPattern><BugCode abbrev="SECLDOS">本地拒绝服务</BugCode>
一切完成就绪后使用Maven进行打包,就生产了供FindBugs集成开发工具插件使用的JAR包,完成安装并重启,即可使用自定义插件对特定问题进行检测。
最终分析的效果图如下图所示:
4 结语
本文介绍了Android集成开发环境Android Studio的代码实时检测工具Code Arbiter的产生原因及代码实现,最后展示了分析的效果。通过Code Arbiter在生产环境中的应用,其检测效果还是相当不错,能够发现很多编码过程中存在的问题。但是Code Arbiter仍然存在许多不足,需要优化。后续将在以下两个方面对工具进行改进:
扩大漏洞检测范围,使Code Arbiter能够囊括Android编码常见安全问题;优化漏洞检测规则,提高检测的准确性,减少误报。
原创文章,作者:admin,如若转载,请注明出处:https://www.qq65hfghe5.com/tg/70877.html