0530-3433334

网站建设 APP开发 小程序

知识

分享你我感悟

您当前位置>首页 >> 知识 >> 软件开发

怎么实现一个IDEA静态代码检测插件的起步阶段?

发表时间:2023-09-12 16:01:19

文章来源:炫佑科技

浏览次数:161

菏泽炫佑科技

怎么实现一个IDEA静态代码检测插件的起步阶段?

这篇文章我想写很久了,但是拖延症​​严重的人就是拖延……

那么本文主要介绍如何实现一个IDEA静态代码检测插件。 现在每个人都在谈论安全左移。 我觉得静态代码检测插件是安全左移的一个很好的实现,所以我想学习一下。

我在写这个插件的初期其实遇到了很多问题。 这些问题肯定是每个想写插件的人都会遇到的。 因此,我简单记录一下我的开发过程,以供参考。

开发环境设置

首先,确保您的插件已成功安装并启用。 一般idea都会自带这个插件。 您只需手动启用它即可。 启用idea后记得重启一下。

然后创建一个项目。 我在这里使用创建项目。 如果您不启用该插件,则不应在此处找到此选项。

通过创建的项目,build中会有这么一项。 文件

会根据这里的字段下载对应版本的依赖包。 这个阶段需要花费很多时间(可能一直下载不完,可以尝试连接代理),可能是因为源在国外。

项目搭建完成后,项目结构大致如下

这里有一个关键文件.xml。 这是插件的配置文件。 这是非常重要的。 它包含以下公共字段。

<idea-plugin>
  
  
  
  <id>com.test.sastid>
  
  <name>AxinSASTname>
  
  <version>1.0version>
  
  <vendor email="wuhu@gmail.com" url="http://wuhu.top">$Company|$Namevendor>
  
  <description>my plugin descriptiondescription>
  
  <change-notes>Initial release of the plugin.change-notes>
  
  <depends>com.intellij.modules.alldepends>
  
  <idea-version since-build="94.539" until-build="192"/>
  
  <actions>
    <action id="FinderAction" class="com.test.finder.FinderAction" text="FileFinder" description="FileFinder">
      <add-to-group group-id="ProjectViewPopupMenu" anchor="first"/>
    action>
  actions>
  
  <extensionPoints>
    ...
  extensionPoints>
  
  <extensions xmlns="com.intellij">
    ...
  extensions>
idea-plugin>

一般来说,按照以上操作应该就可以成功创建插件项目了。 更容易陷入困境的是下载想法依赖项。

编写代码后,我们可以使用此任务来测试我们的插件。 当这个任务**次执行时,它会下载一个jbr()压缩包,然后用它来启动我们的插件。

该任务会在沙盒环境中运行我们编写的插件,不会影响我们当前使用的idea环境。 也就是说,将创建一个新的测试想法,然后我们的插件将在这个测试想法上运行。

为了更清楚的了解idea插件,我们来写一个小demo。 这个demo也是网上*常见的demo。

初体验插件开发

我们使用以下命令创建一个新的

然后填写相应的信息:

上述操作完成后,会在我们的项目目录下生成对应的class文件。 我们重写这个类的方法:

import com.intellij.notification.Notification;
import com.intellij.notification.NotificationDisplayType;
import com.intellij.notification.NotificationGroup;
import com.intellij.notification.Notifications;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.ui.MessageType;

public class TestAction extends AnAction {

    @Override
    public void actionPerformed(AnActionEvent e) {
        // TODO: insert action logic here
        // 这里的testid需要和你刚刚填写的action id保持一致
        NotificationGroup notificationGroup = new NotificationGroup("testid", NotificationDisplayType.BALLOON, false);
        /**
         * content :  通知内容
         * type  :通知的类型,warning,info,error
         */

        Notification notification = notificationGroup.createNotification("测试通知", MessageType.INFO);
        Notifications.Bus.notify(notification);
    }
}

完成上述操作后,我们可以查看.xml文件的变化

你会发现这里多了一个。 这实际上帮助我们自动注册,所以现在你应该能够理解它的用途了。 它帮助我们封装了一些方法,让我们开发插件更加方便。

如果我们刚才没有使用它来创建的话,我们需要手动在.xml文件中注册它,然后在相应的类中实现相应的方法

好了,现在我们的小demo就真正完成了。 到目前为止,您不需要了解上面代码的使用。 你只需要按照我的步骤来就可以了。 至于上面的代码能实现什么,还有什么比亲眼所见更好的呢?

接下来就是验证插件的效果了。 直接执行任务就可以了。

运行这个会创建一个新的想法,然后我们的插件会自动安装在这个想法上。 我们的插件会在工具菜单下注册一个项目,然后点击该项目会在idea的右下角弹出一条消息“测试通知”。

然后我们就可以在idea中看到我们的插件已经成功安装并启用了。

上图是我们的测试插件。 红框中的显示副本可以在.xml文件中配置。

说白了,写插件就涉及到调用各种AP​​I。 想要写好插件,就需要了解SDK提供的各种方法和接口。

我们编写静态代码审计插件的难点在于“应该使用哪个接口来进行代码审计”以及“SDK提供了哪些工具或方法来方便我们完成代码审计?” 只要克服了这两个问题自动化软件开发,那么从AST中查找代码中可能存在的问题就变得一样了。

在idea中进行静态代码审计

首先解决**个问题,代码审计应该使用SDK的哪个接口?

虽然文档写得不好,但好在他上面放了一些代码示例,而且模块和模块(尤其是这个模块)给了我们提示。 通过这两个模块,我知道需要自动化代码检查所使用的函数被调用,那么在此基础上我们可以进一步查询使用文档

既然写到这里了,为了让屏幕前的大家更好的理解它的使用,我简单给大家讲解一下这个模块的一些知识点。 这个简单的demo的主要功能是检测java代码。 比较引用类型时是否存在任何错误,例如错误地使用 != 或 == 而不是类型的 .() 方法?

如果发现错误的使用方式,插件会高亮对应的代码怎么实现一个IDEA静态代码检测插件的起步阶段?,并提供一键修复功能。 另外,这个demo还向我们展示了如何编写测试用例。

这正是我们SAST插件想要做的事情——发现漏洞,突出显示易受攻击的代码,并在可能的情况下提供一键修复功能

当然,除此之外,我们也希望将发现的漏洞代码及时报告给SOC,以便后续人工确认。

首先,我们必须用java来做。 我们需要在build.中配置java。

配置好之后,我们就可以实现一个我们自己的类了。 这个类需要被继承。 那么我们实现的类的总体结构如下:

public class ComparingReferencesInspection extends AbstractBaseJavaLocalInspectionTool{
 public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly){
   return new JavaElementVisitor() {
    public void visitBinaryExpression(PsiBinaryExpression expression) {
     doSomething...
     if(condition){
      holder.registerProblem(expression, "问题描述字符串")
     }
    }
    public void visitXXXXX(){
     xxxxx
    }
   }
 } 
}

*重要的是方法。 上面的代码中有n个方法。 这个方法有什么用呢?

当插件运行时,该方法会检查代码。 你可能会问那是什么?

in 实际上代表了代码中的二项式,例如:

"select * from table where id=" + id
1+2
1-2

上面的表达式被封装在idea中。 代码中的每个二项式都将作为参数传递到 n 方法中。 然后你就可以用这个方法来处理这些二项式,比如判断这个二项式是否是潜在的。 SQL注入语句(如上面**个二项式)

除了n方法之外,还提供了很多访问方法。 这些方法都是为了方便我们的代码。 例如可以访问所有方法调用语句以及所有类似于new Xxx()的语句。

有了上面的基础知识,我们尝试思考如何实现一个简单的插件来检测SQL注入。 我们不考虑特别复杂的SQL注入。 我们只考虑如何检测SQ​​L语句拼接,比如下面的句子。

public test(String id){
 String id2 = '2';
 String sql1 = "select * from table where id="+id;
 String sql2 = "select * from table where id=" + id2;
}

上面两条SQL语句都是二项式表达式,所以我们可以用n来得到。 拿到之后,如何判断是一条SQL语句呢?毕竟这两个二项式表达式都被封装在这个对象中了。 如何通过这个对象判断是否是SQL语句是一个需要解决的问题。

这里我们借用一个插件“”,这个插件可以查看当前源代码文件的AST树,见图

上图左边是我们的源代码,右边是插件窗口。 当我们将光标停留在源代码中的某个位置时,窗口将显示我们在 AST 树中的位置。 反之,当我们在窗口中选择ast树中的某处时,对应的源代码也会被高亮显示。

这个插件可以让我们对解析后的AST树有更清晰的认识。

现在,让我们回到*初的问题。 拿到之后我们如何判断是否是一条SQL语句呢?

实际上

如果你仔细看的话,从上图中可以看到,窗口的下半部分显示了当前对象的所有属性及其值。

您可以看到前两个属性是(左操作数)和(右操作数)。 另外,还有一个属性,上面的截图中没有捕捉到。 该属性指示当前二项式运算符是什么。

常见的运算符有+、-等。

所以,现在如何确定二项式是否是 SQL 语句应该很明显了:

首先判断当前二项式的运算符是否为加号。 如果是加号,则获取左操作数和右操作数,解析出它们的值,然后将它们的值拼接在一起,*后用正则表达式判断是否是sql语句

当然,这只是理想情况。 如果要检测SQL注入,需要考虑多种情​​况。 这里有一些:

public test(String id){
 String id2 = '2';
 String sql1 = "select * from table where id="
 String sql2 = sql1 + id;
 String sql1 += id;
 String sql3 = "select * from table where id=" + id2;
 String sql4 = "select * from" + "table" + id2;
 String sql5 = "select * from table where id=" + getId();
 String sql6 = "select * from table where id=%s";
 sql6.format(id);
}

好吧,看来这就够了。 如果我想更详细的话,我就直接贴出代码,然后逐句注释掉。

那么下面是运行我写的demo插件的效果:

在写了一些通过 AST 进行代码审计的 demo 后,我发现 AST 能做的事情非常有限,而 QL 是自动化代码审计更正确的方法。

炫佑科技专注互联网开发小程序开发-app开发-软件开发-网站制作等

相关案例查看更多