前段时间fastjson报出了漏洞,只要打开setAutoType特性就会存在风险,自己测试环境的一个项目被揪出来了-_-!。虽然改动很小,但就是觉得憋屈。fastjson还是挺好的,想着禁用的话太可惜,用的话又要注意安全,就想着找款工具提示下在用fastjson的时候不要打开这个特性。刚好阿里开源了p3c(https://github.com/alibaba/p3c),一款代码规范的检查工具,有对应的ide插件,能在编码过程中对设置的规则进行提示,便打算对它进行拓展,增加对fastjson检查是否打开setAutoType特性的检查。

 p3c主要包括3部分:

  • PMD实现(p3c-pmd):使用PMDhttps://pmd.github.io/来实现代码规范检查
  • Intellij IDEA插件
  • Eclipse插件

 《阿里巴巴Java开发手册》中的大部分规则都是在p3c-pmd模块中实现的,该部分也是这节研究的主要部分。

1. PMD

 p3c使用了PMD。PMD是一款静态代码扫描工具,该工具可以做到检查Java代码中是否含有未使用的变量、是否含有空的抓取块、是否含有不必要的对象等。PMD使用JavaCC生成解析器来解析源代码并生成AST(抽象语法树),通过对AST的检查可以直接从源代码文本层面来对代码进行检查,在PMD内部称为规则。即是否符合规则指的是,穷举源码各种可能的写法,然后在AST上检查是否出现。而规则的实现,重点便在对AST的处理上。

1.1. AST

 关于AST的介绍网上有很多,可以直接搜索,这里重要提两点:

  • AST是源代码的抽象语法结构的树状表示
  • 抽象语法树并不依赖于原语言的语法,也就是说同语法分析阶段所采用的上下文无关

 PMD使用JavaCC来生成AST。关于JavaCC也可以在网上查看相关资料,这里不多介绍,只要知道JavaCC是一个词法分析生成器和语法分析生成器便行。

1.2. 自定义规则

 PMD官方文档介绍了自定义规则的实现步骤,过程比较清晰,这里不赘述,只介绍下本文需要设计的步骤。

1.2.1. 定义规则集

 PMD的规则需要配置在XML文件中

  • 新建如下的空文件表示规则集
  1. <?xml version="1.0"?>
  2. <ruleset name="Custom Rules"
  3. xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
  4. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  5. xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd">
  6. <description>
  7. My custom rules
  8. </description>
  9. <!-- Your rules will come here -->
  10. </ruleset>
  11. ```
  12. * 在上面的``` ruleset ``` 标签中引用自定义规则
  13. ```
  14. <rule ref="pathToYourOwnClass" />
  15. ```
  16. * 配置规则集
  17. ###### 1.2.2. 配置规则
  18. &emsp;可以在 ``` rule ``` 标签中对某一规则进行配置
  19. * 配置提示消息和告警级别
  20. ```
  21. <rule ref="pathToYourOwnClass"
  22. message="message to show" >
  23. <priority>5</priority>
  24. </rule>
  25. ```
  26. 告警优先级分为1-5个level,1最高,5最低
  27. * 配置运行参数
  28. 可以通过 ``` properties ``` 和 ``` propertie ```对类属性赋值
  29. ###### 1.2.3. 编写规则
  30. &emsp;规则的编写比较简单,PMD已经给我们做好了配套的开发框架和工具,只要确定后规则出现的情况,按照固定的模式去编写即可。
  31. * 确定实现方式
  32. 可以使用纯Java方式实现,也可以使用XPath方式实现。
  33. 对于纯Java方式,PMD框架本身实现了对AST数的遍历,用户只要在遍历各个节点的时候,对自定义规则的各种情况进行分析判断即可,过程类似与DOM文件的SAX解析,以流和事件的方式来解析AST内容。
  34. 对于XPath方式,则是将AST作为一个XML数,以XPath的方式来遍历解析内容。
  35. * 根据测试代码确定可能出现的情况
  36. PMD自带了一个designer,可以用来生成对应代码的AST内容。对于本文需要达到的效果,涉及到如下代码:
  37. ```
  38. import com.alibaba.fastjson.parser.ParserConfig;
  39. public class NegativeExample {
  40. public static void main(String[] args) {
  41. ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
  42. }
  43. }
  44. ```
  45. 在designer中可以得到如下的AST内容
  46. ![file](https://img2018.cnblogs.com/blog/1812801/201910/1812801-20191025160959878-590799600.jpg)
  47. 具体内容这里就不贴出来了,可以下载desigin然后贴上上面的代码就会有。
  48. 对于本文的需求,需要确定在有import ``` ParserConfig ``` 类的时候,调用了 ``` setAutoTypeSupport ``` 方法且参数为 ``` true ```。当然这个条件是不够严谨的,还需要判断是否调用了 ``` ParserConfig ```,也要考虑有通过import导入直接写全限定名的。但考虑到一般的写法,以及ide的格式化处理,这样处理已经可以满足大部分场景了。
  49. * 编写规则实现类
  50. 确定了规则的判断条件,就可以着手写代码了。
  51. 对于Java方式,可以直接继承 ```net.sourceforge.pmd.lang.java.rule.AbstractJavaRule ``` 类,然后重写各种节点的visit方法即可。
  52. 例如如下,用于判断是否有import ``` ParserConfig ``` 类
  53. ```
  54. private final String PARSER_CONFIG_IMPORT_NAME = "com.alibaba.fastjson.parser.ParserConfig";
  55. private boolean hasImport = false;
  56. @Override
  57. public Object visit(ASTImportDeclaration node, Object data) {
  58. if (PARSER_CONFIG_IMPORT_NAME.equals(node.getImportedName())) {
  59. hasImport = true;
  60. }
  61. return super.visit(node, data);
  62. }
  63. ```
  64. 对于XPath方式,可以通过继承 ``` net.sourceforge.pmd.lang.rule.XPathRule ``` 类,重写 ``` setXPath ``` 方法设定对应的XPath即可。上面提到过,可以通过 ``` property ``` 配置对类的属性进行赋值,因而,对于XPat方式,可以在xml配置中进行如下设置来启用XPath。
  65. ```
  66. <rule name="My Rule"
  67. language="java"
  68. message="violation message"
  69. class="net.sourceforge.pmd.lang.rule.XPathRule">
  70. <description>
  71. Rule Description
  72. </description>
  73. <priority>3</priority>
  74. <properties>
  75. <property name="xpath">
  76. <value>
  77. <![CDATA[
  78. --- here comes your XPath expression
  79. ]]>
  80. </value>
  81. </property>
  82. </properties>
  83. ```
  84. ###### 1.2.4. 测试规则
  85. &emsp;PMD推荐对于每个规则,至少要有一个正向和逆向的测试用例,来验证规则出现和不出现的情况。对于规则的测试,PMD也提供了一套框架,只要按照约定好的方式添加xml测试文件即可。
  86. &emsp;PMD约定了几个规则,用来加载测试案例
  87. * 测试类要继承 ``` net.sourceforge.pmd.testframework.PmdRuleTst ```类,该整合了Junt,可以在里面增加需要的测试方法。
  88. * 对于在 ``` src/test/resource ``` 和测试类对应的路径下增加一个xml目录,在增加同第一步同名的xml文件,该文件用于书写测试集。
  89. 例如官网给出的例子
  90. 规则实现类路径如下:
  91. ```
  92. net.sourceforge.pmd.lang.java.rule.bestpractices.AbstractClassWithoutAbstractMethodTest
  93. ```
  94. 测试案例集如下:
  95. ```
  96. src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/AbstractClassWithoutAbstractMethod.xml
  97. ```
  98. xml的规则则可以参考官网介绍,这里不再赘述。
  99. #### 2. p3c-pmd
  100. &emsp;代码规范实现的主要模块,使用pmd来实现。p3c-pmd模块在代码组织上很工整,可以按照相同的模式增加自定义的规则/规则集。
  101. &emsp;对于本文需求,打算在该模块的基础上增加一个extend模块,用于实现自定义规则集。如下,为对应的源码路径好规则集路径
  102. ![file](https://img2018.cnblogs.com/blog/1812801/201910/1812801-20191025161000108-1340099359.jpg)
  103. ![file](https://img2018.cnblogs.com/blog/1812801/201910/1812801-20191025161000368-199680801.jpg)
  104. &emsp;本文采用纯Java方式实现规则,按照1.2.3.节的描述,可以得到如下的实现类

public class AvoidFastJsonAutoTypeSupportRule extends AbstractAliRule {

  1. private final String PARSER_CONFIG_IMPORT_NAME = "com.alibaba.fastjson.parser.ParserConfig";
  2. private final String SET_AUTO_TYPE_SUPPORT_NAME = "setAutoTypeSupport";
  3. private boolean hasImport = false;
  4. @Override
  5. public Object visit(ASTImportDeclaration node, Object data) {
  6. if (PARSER_CONFIG_IMPORT_NAME.equals(node.getImportedName())) {
  7. hasImport = true;
  8. }
  9. return super.visit(node, data);
  10. }
  11. @Override
  12. public Object visit(ASTPrimaryExpression node, Object data) {
  13. if (hasImport) {
  14. int size = node.jjtGetNumChildren();
  15. for (int i = 0; i < size; i++) {
  16. Node child = node.jjtGetChild(i);
  17. String imageName = null;
  18. if (child instanceof ASTPrimaryPrefix) {
  19. ASTPrimaryPrefix prefix = (ASTPrimaryPrefix) child;
  20. imageName = prefix.jjtGetChild(0).getImage();
  21. }else if (child instanceof ASTPrimarySuffix){
  22. ASTPrimarySuffix suffix = (ASTPrimarySuffix) child;
  23. imageName = suffix.getImage();
  24. }
  25. if (imageName == null) {
  26. continue;
  27. }else if (imageName.endsWith(SET_AUTO_TYPE_SUPPORT_NAME)){
  28. ASTPrimarySuffix argumentSuffix = (ASTPrimarySuffix) node.jjtGetChild(i + 1);
  29. try {
  30. List<Node> booleanArgs = argumentSuffix.findChildNodesWithXPath("//PrimaryPrefix/Literal/BooleanLiteral");
  31. if (booleanArgs.size() == 1) {
  32. ASTBooleanLiteral booleanLiteral = (ASTBooleanLiteral) booleanArgs.get(0);
  33. if (booleanLiteral.isTrue()) {
  34. ViolationUtils.addViolationWithPrecisePosition(this, argumentSuffix, data,
  35. I18nResources.getMessage("java.extend.AvoidFastJsonAutoTypeSupportRule.rule.msg" ));
  36. }
  37. }
  38. } catch (JaxenException e) {
  39. e.printStackTrace();
  40. } finally {
  41. break;
  42. }
  43. }
  44. }
  45. }
  46. return super.visit(node, data);
  47. }

}


  1. &emsp;对应规则集中的配置为

java.extend.AvoidFastJsonAutoTypeSupportRule.rule.desc

1



<![CDATA[

Negative example:

import com.alibaba.fastjson.parser.ParserConfig;

  1. public class NegativeExample {
  2. public static void main(String[] args) {
  3. ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
  4. }
  5. }

]]>


  1. &emsp;这里有几点需要注意的,类 ``` AvoidFastJsonAutoTypeSupportRule ``` 继承自 ``` com.alibaba.p3c.pmd.lang.java.rule.AbstractAliRule ```AbstractAliRule继承自AbstractJavaRule,重写了setDescription,setMessageaddViolationWithMessage等方法,这里提到的3个方法,增加了多语言支持。p3c-pmd使用Resource Bundle来提供多语言支持。每个消息都有一个唯一id来对应,p3c-pmd通过重写方法,将方法参数映射为消息的id,以统一消息的配置。如下为本地对应的消息提示内容
  1. <!--extend-->
  2. <entry key="java.extend.AvoidFastJsonAutoTypeSupportRule.rule.msg">
  3. <![CDATA[不要打开fastjson的setAutoTypeSupport特性]]>
  4. </entry>
  5. <entry key="java.extend.AvoidFastJsonAutoTypeSupportRule.rule.desc">
  6. <![CDATA[

说明:fastjson的setAutoTypeSupport特性存在安全漏洞

]]>


  1. &emsp;对于测试,按照1.2.4.的介绍,则有如下的文件路径
  2. ![file](https://img2018.cnblogs.com/blog/1812801/201910/1812801-20191025161000622-547325296.jpg)
  3. 文件内容比较简单,这里就不贴出来了。
  4. &emsp;至此,已经完成了自定义规则的实现,现在就是要把该内容应用到ide上了。首先,需要将该模块进行编译,这里直接保存到本地maven参考,好在本地调试。
  5. &emsp;直接将p3c-pmd的版本升级为2.0.1,然后执行mvn install,可以在本地仓库看到对应的版本
  6. ![file](https://img2018.cnblogs.com/blog/1812801/201910/1812801-20191025161000982-1139222394.jpg)
  7. 有了该版本,则可以在其他模块引用该版本进行新功能调试,下面将以idea-plugin模块为例。
  8. #### 3. idea-plugin
  9. &emsp;idea-plugin主要实现了idea的插件,能够对代码进行实时检查。这里涉及到idea自定义插件的开发,这里就不深入了,网上有很多教程。这里只介绍如何将上面自定义的规则接入该模块。
  10. 1.修改idea-plugin模块的build.gradle文件,开启本地仓库配置,以便从本地直接加载最新的p3c-pmd依赖。

buildscript {

repositories {

maven {

url "https://oss.sonatype.org/content/repositories/snapshots/"

}

maven {

url 'http://dl.bintray.com/jetbrains/intellij-plugin-service'

}

mavenLocal()

mavenCentral()

  1. }
  2. dependencies {
  3. classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
  4. }

}

allprojects {

group 'com.alibaba.p3c.idea'

apply plugin: 'java'

apply plugin: 'kotlin'

apply plugin: 'maven-publish'

  1. sourceCompatibility = 1.8
  2. compileJava.options.encoding = 'UTF-8'
  3. configurations.all {
  4. resolutionStrategy.cacheChangingModulesFor 0, 'seconds'
  5. }
  6. repositories {
  7. mavenLocal()
  8. jcenter()
  9. mavenCentral()
  10. }
  11. dependencies {
  12. compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
  13. testCompile group: 'junit', name: 'junit', version: '4.11'
  14. }

}


  1. 如上,增加了```mavenLocal()```
  2. 2.修改p3c-commonbuild.gradle,更改p3c-pmd的版本为2.0.1
  3. 3.修改p3c-common模块resources/rulesets/java/ali=pmd.xml,增加

```

以增加自定义规则检查。

4.在p3c-common模块下,执行gradle clean buildPlugin,生成对应的插件。

4. 验证

 本地安装该插件,可以得到如下效果

 这里只验证效果,没有真正引入fastjson依赖,也验证了pmd检查的是源码文本。

更多原创内容请搜索微信公众号:啊驼(doubaotaizi)

扩展阿里p3c实现自定义代码规范检查的更多相关文章

  1. Java-idea-Checkstyle自动化代码规范检查

    一.概述 CheckStyle是SourceForge下的一个项目,提供了一个帮助JAVA开发人员遵守某些编码规范的工具.它能够自动化代码规范检查过程,从而使得开发人员从这项重要,但是枯燥的任务中解脱 ...

  2. Jenkins系列——使用checkstyle进行代码规范检查【升级版】

    1.背景 在<Jenkins系列——使用checkstyle进行代码规范检查>一文中完成了ant实现代码规范检查的例子.但存在以下缺陷: 每个作业都需要配置一个不同的checkstyle ...

  3. 玩转Eclipse — 自动代码规范检查工具Checkstyle

    大项目都需要小组中的多人共同完成,但是每个人都有自己的编码习惯,甚至很多都是不正确的.那么如何使小组所有开发人员都遵循某些编码规范,以保证项目代码风格的一致性呢?如果硬性地要求每个开发人员在提交代码之 ...

  4. SwiftLint:代码规范检查工具介绍

    Swift-CodeStyle Checker:SwiftLint 介绍: SwiftLint 是一个用于强制检查 Swift 代码风格和规定的一个工具,基本上以 GitHub's Swift 代码风 ...

  5. swiftlint swift代码规范检查神器

    一大堆的你为什么要用swiftlint,你为什么要codereview,swiftlint到底在做什么,就不多说了,没意义,他就是帮助你写出规范漂亮代码的神器! 安装 官方提供了三种安装的方式 hom ...

  6. IDEA 阿里巴巴代码规范检查插件

    1.问题概要 大家都想写出规范的代码,可规范的标准是什么勒,估计每个人心中的标准都不是完全一致的 在分工合作越来越精细化的时代,我们需要一个最大程度接近公认的规范,这里我们以阿里巴巴的代码规范作为参考 ...

  7. Jenkins系列——使用checkstyle进行代码规范检查

    1.目标 通过jenkins使用checkstyle对代码进行规范检查并生成html报告. 构建采用shell. 2.环境 checkstyle5.7(如果是Linux版本选用tar.gz格式) ap ...

  8. Sonarqube C#静态代码规范检查(一)

    使用说明 代码规范对于每个开发来说重要也重要,说不重要其实也没那么重要,简单点的vs的code analysis也能提供很多的建议,重量级一点的Resharper不仅能提供建议,还提供了更方便快捷的一 ...

  9. PhpStorm添加PHP代码规范检查CodeSniffer(phpcs)和PHP代码静态分析工具Mess Detector(phpmd)

    一.安装 添加镜像,加速下载 ./composer.phar  config -g repo.packagist composer https://packagist.phpcomposer.com ...

随机推荐

  1. Centos7 设置redis开机自启

    Centos7 设置redis开机自启 标签(空格分隔):Linux 环境 Centos7.1 redis-3.0.6 chkconfig方式 **service和chkconfig命令的功能好像都被 ...

  2. git 添加子模块 fatal: You are on a branch yet to be born

    删除与.git / modules /目录下的子模块具有相同路径的文件夹.当子模块添加子模块时,如果子模块的url不正确,则会出现此错误.

  3. 【Win10】时钟精确到秒

    [Win10]时钟精确到秒 前言 想要桌面右下角的时钟"xx:xx:xx"精确到秒,可以使用绿色免费开源软件Dism++,也可以从该软件的代码中读到方法:用注册表实现. 步骤 进入 ...

  4. smartbits国产版本minismb – windows 10 用户界面无法正常显示

    Minismb测试仪表是复刻smartbits的国产版本,是一款专门用于测试智能路由器,网络交换机的性能和稳定性的软硬件相结合的工具.可以通过此工具测试任何ip网络设备的端口吞吐率,带宽,并发连接数和 ...

  5. Kubernetes的Deployment对象使用

    一.什么是Deployment对象 明明ReplicaSet已经可以控制pod的数量了,为什么还需要Deployment? Deploymen实际上一个两层控制器,遵循一种滚动更新的方式来实升级现有的 ...

  6. C#控件及常用属性

    1.窗体(Form) 1.常用属性 (1)Name 属性:用来获取或设置窗体的名称,在应用程序中可通过Name 属性来引用窗体. (2) WindowState 属性: 用来获取或设置窗体的窗口状态. ...

  7. 下载腾讯VIP视频

    1.找到自己想看的VIP视频网页地址,比如我就喜欢看一周一更的天行九歌,链接地址:https://v.qq.com/x/cover/rm3tmmat4li8uul/i0031xd1vjf.html 2 ...

  8. 平行世界中的你还是你吗?--java中的==是否相等

    故事背景 <宇宙追缉令>是黄毅瑜执导的动作科幻类电影,由哥伦比亚三星公司出品,戴尔里·林多.李连杰.杰森·斯坦森领衔主演.影片于2001年11月2日在美国上映.该片讲述了邪恶尤兰,为了成为 ...

  9. 事件--JavaScript

    事件概述 JavaScript 使我们有能力创建动态页面,而事件是可以被 JavaScript 侦测到的行为. 简单理解: 触发--- 响应机制. 网页中的每个元素都可以产生某些可以触发 JavaSc ...

  10. 详解Java多线程锁之synchronized

    synchronized是Java中解决并发问题的一种最常用的方法,也是最简单的一种方法. synchronized的四种使用方式 修饰代码块:被修饰的代码块称为同步语句块,其作用的范围是大括号{}括 ...