FindBugs-IDEA插件的使用

一、 前言

FindBugs是一款Java静态代码分析工具,与其他静态分析工具(如Checkstyle和PMD)不同,FindBugs不注重样式或者格式,它专注于寻找真正的缺陷或者潜在的性能问题,它可以帮助java工程师提高代码质量以及排除隐含的缺陷。有了静态分析工具,就可以在不实际运行程序的情况对软件进行分析。Eclipse中有插件可以帮助查找代码中隐藏的bug,IDEA中也有这款插件。
在FindBugs中,可以安装一个针对代码安全性进行检测的组件,叫做Find-sec-bugs。此组件包含了130种(2019-03-27版本)针对安全性的检测规则,对于我们源码的安全审计工作帮助很大。
这篇文章,我们就介绍下基于IDEA平台的FindBugs插件的安装及使用方法,以及Find-sec-bugs组件的安装方法。

二、安装

打开IDEA,点击左上角的File—Settings进入设置界面,然后点击Plugins进入插件窗口,直接联网进行搜索findbugs,点击Install安装。详情见下图的操作截图。
FindBugs-IDEA插件的使用
FindBugs-IDEA插件的使用

安装完之后,重启IDEA,会发现左下角会出现FindBugs-IDEA的图标。
FindBugs-IDEA插件的使用

接下来我们进行安装findbugs安全规则组件:Find-sec-bugs
在Find-sec-bus插件的官方下载地址:https://find-sec-bugs.github.io/进行下载最新的版本文件。
FindBugs-IDEA插件的使用
打开IDEA进行插件的安装。
依然是进入:File—Settings

点击FindBugs-IDEA,进入FindBugs的设置窗口。点击Plugins下面的加号进行组件的导入,然后选择4.Install plugin from disk。在路径中选择之前下载的插件文件,然后点击OK。详细操作步骤见下面截图。
FindBugs-IDEA插件的使用FindBugs-IDEA插件的使用

这样FindBugs插件和其安全性规则的Find-sec-bugs插件都已经安装完成。

三、 FindBugs的使用说明

1. FindBugs的功能按键

不同的编号的意义为:
FindBugs-IDEA插件的使用
1、分析选中的 Java 文件
2、分析选中的类
3、分析选中的包
4、分析选中的模块 (点击时会询问是否同时分析 test 包中的类)
5、分析整个项目 (点击时会询问是否同时分析 test 包中的类)
6、分析自定义的类(点击进入会有详细的自定义选项)
7、分析被修改的类 (搭配 SVN,Git 使用)
8、分析 changelist 中的类 (搭配 SVN,Git 使用)
9、停止分析
10、清除并且关掉FindBugs工具窗口
11、FindBugs-IDEA帮助
12、根据 BUG 类型分组
13、根据类分组
14、根据包分组
15、根据 BUG 严重级别分组
16、autoscroll to source(自动滚动到可能的bug的源位置,就是如果你选择了此项设置,在点击bug列表时候,在上面的源代码位置,就会自动展现出此BUG发生的源代码。不适用于导入的XML报告,因为没有源代码工程。)
17、展示当前选择的Bug的源代码(此项单纯指的是在FindBugs-IDEA窗口下展示源代码。)
18、搜索功能(可以搜索Bug名称,不能搜索源码)
19、展开所有Bug列表
20、折叠所有Bug列表
21、插件设置
22、导出Bug扫描的报告(可以选择HTML格式和XML格式,HTML的好处是自己观看更直观,XML的好处是可以利用下面23号按钮的功能进行导入查看。)
23、导入Bug扫描的报告(只支持XML格式进行导入)。

2. FindBugs的设置

可以通过两个地方进行FindBugs的设置。第一种是上述的21号按钮。第二种是点击File—Settings,选择FindBugs—IDEA进入设置界面。

需要注意的是:FindBugs的设置,只针对当前的工程。

下面介绍下设置页面的功能描述:

FindBugs-IDEA插件的使用

1) 常规设置General:

1、Compile affected files before analyze 在分析之前进行编译
2.、Analyze affect files affter comlplie 在变动的文件编译之后自动进行分析
3.、Analyze affect files after auto make 在自动Make之后自动分析变动的文件
4.、Run analyze in background 在后台分析,不显示进度条窗口
5.、Active toolwindow on run 在分析过程中展示按钮(工具窗口)

FindBugs-IDEA插件的使用

2) 报告设置Report

1、Analysis effort 分析的深入程度(分析级别)
Minimal—最低级别
Default—默认级别
Maximal—最高级别

2、Minimum rank错误级别
数字越小越严重,配置数字越小筛选的范围也越小。例如选择20-Of Concern既显示最多的BUG数。反之,选择1-Scariest既只显示符合规则的部分BUG。

3、Minimum confidence 报告中显示Bug的最低等级
Hign—高等级(选择此项只显示高等级BUG)
Medium—中等级
Low –低等级(选择此项显示所有BUG)

4、Bad pratice
编程的坏习惯
主要是命名问题,比如类名最好以大写开头,字符串不要使用等号不等号进行比较,可能会有异常最好用try-catch包裹的代码,方法有返回值但被忽略等等,这些如果不想改可以直接忽略.
HE:类中equals()与hashCode()没有同时定义,或者使用了错误的对象的hashCode()或equals()。
SQL:Statement 的execute方法调用了非常量的字符串;或Prepared Statement是由一个非常量的字符串产生。
DE: 方法终止或不处理异常,一般情况下,异常应该被处理或报告,或被方法抛出。

5、Malicious code vulnerability
恶意代码漏洞
听起来很吓人呀,主要是一些属性直接使用public让别的类来获取,建议改为private并为其提供get/set方法. 还有一些public的静态字段,可能会被别的包获取之类的. 这些也需要根据项目具体情况来,个人意见,在有的不重要类,有时直接公开使用属性,可能更为便捷.如果你认为这些不需要修改,完全可以忽略.

6、correctness
代码的正确性 这一项应该算是最重要的了
主要是没有对变量进行不为空判定,在特殊情况可能发生空指针异常。下面列举几个:
NP: 空指针被引用;在方法的异常路径里,空指针被引用;方法没有检查参数是否null;null值产生并被引用;null值产生并在方法的异常路径被引用;传给方法一个声明为@NonNull的null参数;方法的返回值声明为@NonNull实际是null。
Nm: 类定义了hashcode()方法,但实际上并未覆盖父类Object的hashCode();类定义了tostring()方法,但实际上并未覆盖父类Object的toString();很明显的方法和构造器混淆;方法名容易混淆。
SQL:方法尝试访问一个Prepared Statement的0索引;方法尝试访问一个ResultSet的0索引。
UwF:所有的write都把属性置成null,这样所有的读取都是null,这样这个属性是否有必要存在;或属性从没有被write。

7、performance
性能
主要是一些无用的代码,比如声明了没有用到的属性等等
NP: 空指针被引用;在方法的异常路径里,空指针被引用;方法没有检查参数是否null;null值产生并被引用;null值产生并在方法的异常路径被引用;传给方法一个声明为@NonNull的null参数;方法的返回值声明为@NonNull实际是null。
Nm: 类定义了hashcode()方法,但实际上并未覆盖父类Object的hashCode();类定义了tostring()方法,但实际上并未覆盖父类Object的toString();很明显的方法和构造器混淆;方法名容易混淆。
SQL:方法尝试访问一个Prepared Statement的0索引;方法尝试访问一个ResultSet的0索引。
UwF:所有的write都把属性置成null,这样所有的读取都是null,这样这个属性是否有必要存在;或属性从没有被write。

8、security—我们进行源码安全审计主要是勾选此项
安全性。后续会针对此处有详细的介绍。

9、Dodgy code
糟糕的代码
比如一个double/float被强制转换成int/long可能会导致精度损失,一些接近零的浮点数会被直接截断,事实上我们应该保留. 这里顺便提一点,这两天看了《app研发录》,在规范代码,尽量规避错误这方面我也有了一些收获. 在类型转换的时候,我们应该为类型转换提供一个安全的转换方法,因为我们永远不会知道,我们的app在用户手里会发生什么,所以我们要尽可能的去减少这种发生错误的可能.比如使用switch的时候没有提供default。多余的空检查,就是不可能为空的值,增加了不为空判断,这是没有必要的。属于代码冗余不安全的类型转换等等。 这项太多了,就不一一列举了。

10、Experimental
实验 (参考)
https://blog.****.net/jdsjlzx/article/details/21472253/
1.LG: Potential lost logger changes due to weak reference in OpenJDK (LG_LOST_LOGGER_DUE_TO_WEAK_REFERENCE)
OpenJDK的引入了一种潜在的不兼容问题,特别是,java.util.logging.Logger的行为改变时。它现在使用内部弱引用,而不是强引用。–logger配置改变,它就是丢失对logger的引用,这本是一个合理的变化,但不幸的是一些代码对旧的行为有依赖关系。这意味着,当进行垃圾收集时对logger配置将会丢失。例如:
public static void initLogging() throws Exception {
Logger logger = Logger.getLogger(“edu.umd.cs”);
logger.addHandler(new FileHandler()); // call to change logger configuration
logger.setUseParentHandlers(false); // another call to change logger configuration
}
该方法结束时logger的引用就丢失了,如果你刚刚结束调用initLogging方法后进行垃圾回收,logger的配置将会丢失(因为只有保持记录器弱引用)。
public static void main(String[] args) throws Exception {
initLogging(); // adds a file handler to the logger
System.gc(); // logger configuration lost
Logger.getLogger(“edu.umd.cs”).info(“Some message”); // this isn’t logged to the file as expected
}
2.OBL: Method may fail to clean up stream or resource (OBL_UNSATISFIED_OBLIGATION)
这种方法可能无法清除(关闭,处置)一个流,数据库对象,或其他资源需要一个明确的清理行动。
一般来说,如果一个方法打开一个流或其他资源,该方法应该使用try / finally块来确保在方法返回之前流或资源已经被清除了。这种错误模式基本上和OS_OPEN_STREAM和ODR_OPEN_DATABASE_RESOURCE错误模式相同,但是是在不同在静态分析技术。我们正为这个错误模式的效用收集反馈意见。

11、Multithreaded Correctness
多线程问题
DL_SYNCHRONIZATION_ON_BOOLEAN
Synchronization on Boolean could lead to deadlock 该代码同步一个封装的原始常量,例如一个Boolean类型
private static Boolean inited = Boolean.FALSE; … synchronized(inited) { if (!inited) { init(); inited = Boolean.TRUE; } } …
由于通常只存在两个布尔对象,此代码可能是同步的其他无关的代码中相同的对象,这时会导致反应迟钝和可能死锁
DL_SYNCHRONIZATION_ON_BOXED_PRIMITIVE
Synchronization on boxed primitive could lead to deadlock
该代码同步一个封装的原始常量,例如一个Integer类型。
private static Integer count = 0; … synchronized(count) { count++; } …
由于Integer对象可以共享和保存,此代码可能是同步的其他无关的代码中相同的对象,这时会导致反应迟钝和可能死锁
DL_SYNCHRONIZATION_ON_SHARED_CONSTANT
Synchronization on interned String could lead to deadlock
同步String类型的常量时,由于它被JVM中多个其他的对象所共有,这样在其他代码中会引起死锁。

12、Internationalization
国际化
当对字符串使用upper或lowercase方法,如果是国际的字符串,可能会不恰当的转换。

3) 过滤器设置Filter

此功能作用是:过滤器将针对一组条件的错误实例进行匹配。通过定义过滤器,您可以选择错误实例进行特殊处理; 例如,将其排除或包含在报告中。
使用方法:将相应的规则作成一份 XML文档,然后,在配置页面中导入这份配置文档即可。
如何制作相应的过滤器XML文件,可以参考官方文档:
http://findbugs.sourceforge.net/manual/filter.html

4) 扫描规则配置Detector

FindBugs-IDEA插件的使用
此处是选择你想使用的检测规则。
Provider:根据规则提供者分类,我们这里分成两类(Find security Bugs和FindBugs)
Speed:根据扫描速度进行分类
Bug Category:根据规则类别进行分类:例如Security安全类。
鼠标点击规则名称,右面的Description会显示相应的描述。

5) Bug注解Annotate

默认设置即可,主要是图标和注解的显示,意义不大。

6) 导入设置文件Share

FindBugs-IDEA插件的使用

此功能支持Sonar和FindBugs的配置文件导入。导入之后,系统会直接识别导入的设置,不会根据当前界面的设置进行执行。设置文件只能是XML格式的。我们在进行源码的安全性扫描的时候,设置一般是固定的,可以导出一份设置文件进行留存,在其他项目的时候直接导入即可使用。
导出的按钮为上图的红色圆圈处的Export。导入的地方有两个入口,都在上图中标识了红色方框。

3. FindBugs的执行

FindBugs-IDEA插件的使用

编号的相应功能如下:
1.分析选中文件
2.分析包下面的所有文件
3.分析整个Module下的所有文件
4.分析整个Project下的所有文件
5.分析自定义选择的一些文件(点击按钮之后就能看到如何自定义)
6.分析所有修改的文件
7.分析changelist中的文件

分析完之后就会出现结果面板

FindBugs-IDEA插件的使用

点击对应的item在右边会定位到具体的代码

FindBugs-IDEA插件的使用