classfinal介绍
ClassFinal是一款java class文件安全加密工具,支持直接加密jar包或war包,无需修改任何项目代码,兼容spring-framework;可避免源码泄漏或字节码被反编译。
Gitee : ClassFinal: Java字节码加密工具
- 无需修改原项目代码,只要把编译好的jar/war包用本工具加密即可。
- 运行加密项目时,无需求修改tomcat,spring等源代码。
- 支持普通jar包、springboot jar包以及普通java web项目编译的war包。
- 支持spring framework、swagger等需要在启动过程中扫描注解或生成字节码的框架。
- 支持maven插件,添加插件后在打包过程中自动加密。
- 支持加密WEB-INF/lib或BOOT-INF/lib下的依赖jar包。
- 支持绑定机器,项目加密后只能在特定机器运行。
- 支持加密springboot的配置文件。
背景
接到一项任务,由于涉及知识产权保护,需要对关键代码片段进行加密处理(核心库)。因此,我选择了ClassFinal工具来实现字节码层面的加密。
使用步骤
- 核心库工程引入插件依赖
<plugin> <!-- https://gitee.com/roseboy/classfinal --> <groupId>net.roseboy</groupId> <artifactId>classfinal-maven-plugin</artifactId> <version>1.2.1</version> <configuration> <password>000000</password><!--加密打包之后pom.xml会被删除,不用担心在jar包里找到此密码--> <packages>com.yourpackage,com.yourpackage2</packages> </configuration> <executions> <execution> <phase>package</phase> <goals> <goal>classFinal</goal> </goals> </execution> </executions> </plugin>
- 运行mvn package时会在target下自动加密生成yourproject-encrypted.jar
- 将核心库依赖到spring boot项目中
- 配置启动命令
-javaagent:yourproject-encrypted.jar="-pwd 000000"
问题改造
IDEA中启动运行一切正常,打包成jar包启动后运行到核心包代码块解密失败,代码无法正常执行?
问题原理
Spring FatJar使用了LaunchedURLClassLoader去加载FatJar中的class和jar嵌套的jar(即jar in jar),显然按照这个逻辑核心包代码块也交由LaunchedURLClassLoader去加载。但是我们使用了javaagent:yourproject-encrypted.jar去执行字节码解密,而代理包中的class是默认交由AppClassloader去加载的,Classfinal默认生成的代理包又包含了所有的核心包代码块(只需用到Classfinal解密代码),这就导致了问题的出现。因为LaunchedURLClassLoader是AppClassLoader的子类加载器,当核心包里面的类调用到被LaunchedURLClassLoader加载的类时会报ClassNoFound。
举个例子:
一、核心库代码String2DateConvert
public class String2DateConvert implements Converter<String, Date> {
@Override
public Date convert(String s) {
if (StringUtils.isNotBlank(s)) {
DateFormat dtf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
return dtf.parse(s);
} catch (ParseException e) {
log.error("日期格式转换失败; {}", e.getMessage());
}
}
return null;
}
}
二、spring boot项目引用核心包代码
public void test() {
String2DateConvert string2DateConvert = new String2DateConvert();
string2DateConvert.convert("2023-01-01");
}
三、其中核心库引用的StringUtils来自apache.commons.lang3包,该第三方包是交由外部LaunchedURLClassLoader。根据双亲委派机制,是无法从AppClassLoader拿到LaunchedURLClassLoader加载的类,因此会报:org.apache.commons.lang.StringUtils NoClassDefFoundError
解决方式
其实就是将代理包中的非解密代码删除掉
源码修改如下:先打包核心包,再打包代理包
预告:如何支持多重jar包解密,即spring boot包也进行一层加密?Classfinal问题处理及改造升级(二)