# 代码漏扫工具

author:韩皖

createTime:2022-5-16

updateTime:2022-5-16


2022-05-16: 培训结束

# 使用教程

# 代码提交

  • 登录 SonarQube 服务,点击新增项目

  • 在新增项目的界面,填写 项目名称项目标识 (项目标识全局唯一),然后再点击设置, 进入二级界面

  • 进入二级界面后选择 手工 方式分析项目,创建令牌,并记录下令牌的值

  • 在pom文件中添加属性 sonar.host.urlsonar.login, 值为上一步骤创建的令牌值

  • 在项目的根目录下执行命令(后续的代码提交只需执行该命令,以上的步骤省略)

    # 中括号中的值可选,如果没有在pom文件中的属性中配置, 则必填
    mvn clean verify sonar:sonar [-Dsonar.host.url=''] [-Dsonar.login='']
    
  • 构建成功后, 登录后端 SonarQube 服务,即可看到提交记录,该记录简略地显示了各个指标项值

# 处理漏扫问题

  • 进入项目的问题界面 , 分为左右两部分,左边为各种过滤筛选条件,右边是Bug的详情信息,违反了什么校验规则

  • 过滤筛选后,点击Bug标题右边的 为何是问题,界面底部有一个弹窗,弹窗中有该规则的详细说明,并且会有对应的正例反例

  • 了解规范后,点击 打开 ,里面的流程就跟禅道差不多了,有 确认、解决、误判、标记为不会修复等选项

# Bug示例

  1. Use try-with-resources or close this "FileOutputStream" in a "finally" clause.

    public static void uploadFile(byte[] file, String filePath, String fileName) throws Exception {
        File targetFile = new File(filePath);
        if (!targetFile.exists()) {
            targetFile.mkdirs();
        }
        // 可能造成资源泄漏,应使用 try-with-resources 或在 finally 中关闭资源 
        FileOutputStream out = new FileOutputStream(filePath + "/" + fileName);
        out.write(file);
        out.flush();
        out.close();
    }
    
    // ---》 改造后
    public static void uploadFile(byte[] file, String filePath, String fileName) throws Exception {
        File targetFile = new File(filePath);
        if (!targetFile.exists()) {
            targetFile.mkdirs();
        }
        try(FileOutputStream out = new FileOutputStream(filePath + "/" + fileName)){
            out.write(file);
        }
    }     
    
  2. Either re-interrupt this method or rethrow the "InterruptedException" that can be caught here.

    ​ 中断是线程间通信的一种方式,一个线程向另一个线程发起中断请求后,接收到中断信号的线程应显示地处理它。如清除中断信号继续业务处理,或者停止业务处理继续向上层调用者传播中断异常

    // 忽略中断异常,不做处理
    try {
        ...业务处理...
        Thread.sleep(50);
    } catch (InterruptedException e) {
        ...ignore...
    }
    
    // ---》 改造后
    try {
        ...业务处理...
        Thread.sleep(50);
    } catch (InterruptedException e) {
        Thread.interrupted();
    }
    
  3. Cognitive Complexity of methods should not be too high

    代码中出现过多的 if 等分支语句,逻辑处理过于复杂,可读性降低

    反例:如P010处理抄表结果返回时,其中一个步骤有15个分支

    改造后:仅剩下三四个分支

  4. This method's return value is marked "javax.annotation.Nonnull" but null is returned

    该示例中,在接口的上方通过注解 @NotNull 标记方法的放回值不为空,但在实现里却存在返回Null的情况

    @Override
    @Nonnull
    public Template createTemplate(@Nonnull NotifyType type, @Nonnull TemplateProperties prop) {
        Map<String, TemplateProvider> templateProviders = providers.get(type.getId());
        if (templateProviders.isEmpty()){
            log.info("不支持的通知类型【{}】", type.getId());
            return null;
        }
        TemplateProvider templateProvider = templateProviders.get(prop.getProvider());
        if (templateProvider == null){
            log.info("不支持的服务商【{}】", prop.getProvider());
            return null;
        }
        return templateProvider.createTemplate(prop);
    
    }
    
  5. Prevent "int" promotion by adding "& 0xff" to this expression.

    ​ 该示例中是一个byte类型的值与一个int类型执行位运算,由于byte类型的数值在执行运算时会隐式类型提升为int, 所以当byte值 > 127 时转换为int型时就会变为一个负数,出现bug。 所以正确的方式是在代码中显示地将其转换为正确的int值

    int = getByte() | (1 << 4)
    // ---> 改造后
    int = (getByte() && 0xff) | (1 << 4)