如何用lint扫出不安全代码
点击上方蓝字关注我们噢~
01
Lint是什么
Lint是google提供的一款静态代码扫描工具,目的是帮助开发者发现代码的质量问题。
相对于其他的工具,Lint有如下优势:
1)功能强大,支持java文件、class文件、资源文件、Gradle等文件的检测。
2)与android studio天然集成,可一键完成lint检测。
3)Lint专为android设计,规则丰富,原生已提供几百个实用规则。
4)扩展性强,支持自定义lint规则
......
02
Lint的原理
App源文件:包含组成Android项目的文件,如java、Kotlin、xml等Lint.xml: lint工具的配置文件,可根据业务场景调整问题的严重级别,或忽略某项检测项。
通过上图,可推断大致流程,lint Tool加载App Source文件及配置文件,然后根据内置规则及定制规则解析文件,最终生成lint out的报告。
根据推测,我们去分析Lint的源码,结果基本符合我们的猜想。整个lint工具包含三个核心库文件:lint.jar,lint-api.jar,lint-checks.jar。
Lint.jar是整个lint的核心及入口,并在lint.jar中调用lint-api.jar及lint-checks.jar。
Lint-api.jar主要是对api进行一些封装,而lint-checks主要是内置规则的一些实现,下文将简单介绍整个lint的加载过程。
Main中run方法包含lint工具的处理流程。Run函数主要流程如下:
当规则准备好以后,client开始run,进入实际的分析流程。
Client的run方法实际调用driver的analyze()方法,driver实际为lint-api.jar中LintDriver。analyze()方法调用checkProject进行项目的检查。
CheckProject方法又继续调用runFileDetectors进行分析。
至此,整个规则加载及检测流程基本清晰。
03
Lint的重要概念
Issue:表示一条规则。
IssueRegistry:用于注册Issue。自定义的Lint最终会生成jar包,jar包的Manifest须指向IssueRegistry类。
Detector:检测单元。每个Issue对应一个Detector。
Scope:声明Detector作用域,即扫描代码的范围,如java源文件、xml资源文件、Gradle文件等。
Scanner:扫描单元。扫描并发现代码中的Issue。每个Detector可以实现一个或多个Scanner。自定义Lint主要工作就是实现Scanner。
04
自定义lint
原理介绍差不多了,大家一定迫不及待想看看到底如何自定义lint吧。下面将介绍如何创建自定义lint。
创建Java Library
Android Studio中选择新建Module,选择Java Library
具体的创建过程不详细叙述,这里特别说明几处重要的注意项:
Gradle Plugin版本,请选择2.3.3,Gradle 版本选择3.3,否则一些包会找不到
项目目录下build.gradle修改,重点是依赖的版本号及maven目录
根目录下build.gradle文件
编写自定义lint
Scanner编写,通过getApplicableMethodNames定义关注的方法,这里我们只关心setSeed的方法。
然后在visitMethod中实现具体的逻辑,如当检查到setSeed方法时,我们需要判断方法的Class信息、参数信息等。如果不符合预期,则打印报告。详情如下:
创建aar库
由于最终需要将jar集成到android工程中,所以我们需要将jar打包成aar文件,方便集成到android工程中。
修改aar的build.gradle文件,建立和jar之间关系,最终将jar打包到aar中。详情如下:
最终执行build,生成libaar-debug.aar
自定义Lint集成
将libarr-debug.aar包放到项目目录的libs目录下,如果没有可以新建一个libs目录。然后在build.gradle中引入aar,具体可以参考下图:
接下来编写测试代码,看看自定义lint规则是否生效。测试代码如下:
测试代码中,当我们直接使用setSeed时,Android Studio显示红色波浪线,提示错误。报错原因是不符合VSecureRandomForTest规则的要求,而VSecureRandomForTest正是我们上文自定义的lint规则,证明规则生效了。
当然,当我们build工程的时候,android studio也会自动执行lint检查。当检测到error时,会停止build的执行,并给出代码行及问题的原因,所以排查起来也是相对方便。具体如下图:
Lint调试
在规则项目中,建立remote,选择自己的代码模块,其他默认参数
在测试项目中,build项添加VM选项,VM选项可以从第一步的remote中拷贝,然后把suspend改为yes,具体如下图所示
在测试项目build.gradle中添加lint配置如下:
以debug方式运行测试项目,然后将规则项目attach到测试项目中,就可以调试了,如下所示
▼
总结
自定义lint集成的过程中,踩了很多坑,大部分是环境的问题,如gradle的版本、android studio的版本等。
整个环境打通后,后续的工作就是研究规则编写。这部分内容,一方面需要理解lint的重要概念、加载原理,内容上文已介绍;另一方面需要贴合自身的业务,这部分不详细阐述。
本文主要起抛砖引玉的作用,欢迎拍砖。
更多精彩阅读
如何用OLLVM来保护你的关键代码
一文读懂 | 内置安全成熟度模型BSIMM
像攻击者一样思考:论威胁分析中的建模模型
长按关注 更多安全技术干货等你发现