SpringBoot3.2 Proguard代码混淆优化
引言
近期项目做了SpringBoot3.2的升级,以前关于项目中混淆代码的配置也做了下优化。
在这里,与大家简单分享下相关配置,有什么问题欢迎讨论。
环境
组件名称 | 版本 |
---|---|
JDK | 17 |
SpringBoot | 3.2.0 |
Gradle | 8.5 |
ProGuard | 7.4.2 |
项目集成ProGuard
参考github上progaurd官方提供的配置,选择了7.4.2版本,但是使用此配置,项目编译直接失败。
报错信息:Could not get unknown property 'ProGuardTask' for project ':proguard-example-config' of type org.gradle.api.Project
于是根据相应的错误提示,修改了相关配置,修改后的配置关键点如下:
import proguard.gradle.ProGuardTask
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("com.guardsquare:proguard-gradle:7.4.2")
}
}
tasks.register('proguard', ProGuardTask) {
configuration file('proguard.pro')
injars(tasks.named('jar').flatMap { it.archiveFile })
def javaHome = System.getProperty('java.home')
if (System.getProperty('java.version').startsWith('1.')) {
libraryjars "${javaHome}/lib/rt.jar"
} else {
libraryjars "${javaHome}/jmods/java.base.jmod", jarfilter: '!**.jar', filter: '!module-info.class'
}
verbose()
outjars layout.buildDirectory.file("libs/${project.name}-minified.jar")
}
引入之后,重新build
一下,就可以看到proguard task
了,执行该任务,就可以在build/libs
下看到相应的混淆Jar包
混淆配置
好了,看到这,终于到了这篇文章的重点了。
在我们项目中,混淆的代码主要是一些自研中间件的相关配置。在对外项目中,只需要引入这个中间件Jar包即可,不需要做项目中做额外配置。
混淆原则
了解到此需要之后,我们就可以简单总结出几个原则对代码做混淆了。
-
对外使用的类不做混淆
-
Spring相关的类不做混淆
-
重写的方法、get/set方法不做混淆
-
异常、注解、枚举不做混淆
混淆配置文件
混淆的配置文件如下:proguard.pro
# JDK目标版本17
-target 17
# 禁用shrink(删除未使用的类和成员)
-dontshrink
# 禁用优化(字节码级别的优化)
-dontoptimize
# 忽略打包时的警告信息
-ignorewarnings
# 不跳过非公共类文件和成员
-dontskipnonpubliclibraryclasses
-dontskipnonpubliclibraryclassmembers
# 类名不使用混合大小写
-dontusemixedcaseclassnames
# 优化时允许访问并修改有修饰符的类和类的成员
-allowaccessmodification
# 混淆类名之后,对使用Class.forName("className")之类的地方进行相应替代
-adaptclassstrings
# 保留所有包名
-keeppackagenames
# 使用唯一的类成员名称
-useuniqueclassmembernames
# 保留异常、注解等特殊信息,避免影响 Spring Boot 启动
-keepattributes Exceptions,InnerClasses,Signature?Deprecated,SourceFile,LineNumberTable,LocalVariable*Table,*Annotation*,SyntheticjEnclosingMethod
# 保留所有的set/get方法
-keepclassmembers public class * {
void set*(***);
*** get*();
}
## 保留外部调用类
-keep class com.zl.exaplme.util.MinIOUtil { *; }
# 保留带有 Spring 相关注解的类、字段和方法
-keepclassmembers class * {
@org.springframework.beans.factory.annotation.Autowired *;
@org.springframework.beans.factory.annotation.Qualifier *;
@org.springframework.beans.factory.annotation.Value *;
@org.springframework.beans.factory.annotation.Required *;
@org.springframework.context.annotation.Bean *;
@org.springframework.context.annotation.Primary *;
@org.springframework.boot.context.properties.ConfigurationProperties *;
@org.springframework.boot.context.properties.EnableConfigurationProperties *;
@javax.annotation.PostConstruct *;
@javax.annotation.PreDestroy *;
}
# 保留实现 Serializable 接口的类
-keep class * implements java.io.Serializable { *; }
# 保留实现 CommandLineRunner 接口的类
-keep class * implements org.springframework.boot.CommandLineRunner { *; }
## 保留使用 @Configuration 注解的类
#-keep @org.springframework.context.annotation.Configuration class * { *; }
#
## 保留使用 @Component 注解的类
#-keep @org.springframework.stereotype.Component class * { *; }
#
## 保留使用 @Service 注解的类
#-keep @org.springframework.stereotype.Service class * { *; }
# 保留使用 @ConfigurationProperties 注解的类
-keep @org.springframework.boot.context.properties.ConfigurationProperties class * { *; }
# 保留使用 @Slf4j 注解的类和生成的 log 字段
-keep @lombok.extern.slf4j.Slf4j class * {*;}
-keepclassmembers class * {
lombok.extern.slf4j.Slf4j log;
}
# 保留枚举类的所有成员
-keepclassmembers enum * { *; }
# 保留主方法
-keepclasseswithmembers public class * { public static void main(java.lang.String[]); }
# 保留源文件和行号信息
-renamesourcefileattribute SourceFile
-keepattributes SourceFile,LineNumberTable
# 忽略所有的警告信息
-dontwarn *
# 混淆字典
-applymapping mapping.map
SpringBoot自动注入与混淆Mapping映射
由于我们混淆的主要是中间件代码,使用了SpringBoot的自动注入机制,3.2版本的spring.factories
变更为新的方式,这里需要额外注意一下。
在这里配置的是类的全路径,但是在混淆之后,类名发生了变化。
为了解决这个问题,以及做到更好的混淆,可以使用自定义的混淆字典,在proguard.pro
同级目录下新增一个mapping.map
文件,在这里定义混淆前后的类名映射。
com.zl.exaplme.config.MinIOAutoConfiguration -> com.zl.exaplme.config.xyz:
如将 MinIOAutoConfiguration
混淆成xyz
。
同时将自动注入的类全路径修改为混淆后的类名:com.zl.exaplme.config.xyz
总结
经过以上步骤,就大致完成了一个SpringBoot Starter的代码混淆。
转载自:https://juejin.cn/post/7376186315644174345