Spring boot使用ProGuard实现代码混淆
SpringBoot 玩一玩代码混淆,防止反编译代码泄露
代码混淆常见于安卓的apk安装文件, 服务端的代码因为不易被普通用户接触到, 所以混淆不多。但是某些场景下, 比如:项目需要部署到客户机器上, 就会有泄露代码逻辑的风险。
不过需要知道的是:使用proguard混淆代码只能增加阅读和理解的难度, 并不能百分百保证代码安全。也即是达到让开发人员看到这头痛的代码有99.99999%的冲动放弃阅读,拍桌子说还不如我重写一遍逻辑。
附:proGuard官网
因为Java代码是非常容易反编译,况且Springboot和Android开发的应用程序都是用Java代码写的,为了很好的保护Java源代码,我们需要对编译好后的class文件进行混淆。
ProGuard是一个混淆代码的开源项目,它的主要作用是混淆代码,殊不知ProGuard还包括以下4个功能:
压缩(Shrink):检测并移除代码中无用的类、字段、方法和特性(Attribute)。
优化(Optimize):对字节码进行优化,移除无用的指令。
混淆(Obfuscate):使用a,b,c,d这样简短而无意义的名称,对类、字段和方法进行重命名。
预检(Preveirfy):在Java平台上对处理后的代码进行预检,确保加载的class文件是可执行的。
建议逐个java包定义混淆规则,这样思路更清晰 ;
本文基于springboot2.x + maven + proguard进行代码混淆。
proguard是最为广为使用的工具之一,可是用他的客户端方式来混淆springboot项目的时候最后总得不到可执行的jar。后来发现了proguard-maven-plugin这个插件,所有proguard的指令都可以在pom中定义实现,本文采用proguard-maven-plugin方案。
#指定Java的版本
-target 1.8
#proguard会对代码进行优化压缩,他会删除从未使用的类或者类成员变量等,shrink这个功能一般最好别用,所以这里添加了,我就遇到过启动jar的时候不支持压缩jar的问题
-dontshrink
#是否关闭字节码级别的优化,如果不开启则设置如下配置
-dontoptimize
#混淆时不生成大小写混合的类名,默认是可以大小写混合
-dontusemixedcaseclassnames
# 对于类成员的命名的混淆采取唯一策略
-useuniqueclassmembernames
#混淆时不生成大小写混合的类名,默认是可以大小写混合
-dontusemixedcaseclassnames
#混淆类名之后,对使用Class.forName('className')之类的地方进行相应替代
-adaptclassstrings
#对异常、注解信息予以保留
-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,*Annotation*,EnclosingMethod
# 此选项将保存接口中的所有原始名称(不混淆)-->
-keepnames interface ** { *; }
# 此选项将保存所有软件包中的所有原始接口文件(不进行混淆)
#-keep interface * extends * { *; }
#保留参数名,因为控制器,或者Mybatis等接口的参数如果混淆会导致无法接受参数,xml文件找不到参数
-keepparameternames
# 保留枚举成员及方法
-keepclassmembers enum * { *; }
# 不混淆所有类,保存原始定义的注释-
-keepclassmembers class * {
@com.baomidou.mybatisplus.annotation *;
@org.springframework.context.annotation.Bean *;
@org.springframework.beans.factory.annotation.Autowired *;
@org.springframework.beans.factory.annotation.Value *;
@org.springframework.stereotype.Service *;
@org.springframework.stereotype.Component *;
}
#忽略warn消息
-ignorewarnings
#忽略note消息
-dontnote
#打印配置信息
-printconfiguration
# 不混淆controller入口类
-keep class com.edevp.modules.store.dto.*
-keep class com.edevp.modules.**.*Impl
-keep class com.edevp.modules.store.web.* {*;}
-keep class com.edevp.modules.store.entity.* {*;}
-keep public class com.edevp.modules.store.StoreApplication {
public static void main(java.lang.String[]);
}
下面这些代码是用来指定哪些包不被混淆,注意将包路径改为你自己的
<option>-keep class com.demo.data.jpa.JpaApplicationoption>
<option>-keep class com.demo.data.jpa.base.* {*;}option>
<option>-keep class com.demo.data.jpa.entity.* {*;}option>
<option>-keep class com.demo.data.jpa.model.* {*;}option>
<option>-keep class com.demo.data.jpa.controller.* {*;}option>
对应配置文件方式:
# 不混淆controller入口类
-keep class com.edevp.modules.store.dto.*
-keep class com.edevp.modules.**.*Impl
-keep class com.edevp.modules.store.web.* {*;}
-keep class com.edevp.modules.store.entity.* {*;}
-keep public class com.edevp.modules.store.StoreApplication {
public static void main(java.lang.String[]);
}
说明:
-keep class 类/包.** 表示保留类名;
-keepclassmembers class 类/包.**{ *;} 表示保留类下边的所有变量,均不混淆。
在pom.xml中配置插件
<plugins>
<plugin>
<groupId>com.github.wvengengroupId>
<artifactId>proguard-maven-pluginartifactId>
<version>2.6.0version>
<executions>
<execution>
<phase>packagephase>
<goals>
<goal>proguardgoal>
goals>
execution>
executions>
<configuration>
<injar>${project.build.finalName}.jarinjar>
<outjar>${project.build.finalName}.jaroutjar>
<obfuscate>trueobfuscate>
<proguardInclude>${project.basedir}/proguard.cfgproguardInclude>
<libs>
<lib>${java.home}/lib/rt.jarlib>
<lib>${java.home}/lib/jce.jarlib>
<lib>${java.home}/lib/jsse.jarlib>
libs>
<inLibsFilter>!META-INF/**,!META-INF/versions/9/**.classinLibsFilter>
<outputDirectory>${project.basedir}/targetoutputDirectory>
<options>
options>
configuration>
plugin>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
<version>2.6.8version>
<executions>
<execution>
<goals>
<goal>repackagegoal>
goals>
<configuration>
<mainClass>com.edevp.modules.store.StoreApplicationmainClass>
configuration>
execution>
executions>
plugin>
plugins>
build>
然后点击package,正常执行编译打包流程就可以 :
打包之后
在target目录下会生成5个文件:
jpa-0.0.1-SNAPSHOT.jar混淆后的Spring boot
jar,里面包含完整的项目结构,可以运行,这个就是我们本文的产出物; proguard_map.txt 混淆内容的映射;
proguard_seed.txt 参与混淆的类; 还有2个未混淆的原始jar包。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>com.erbadagang.data.jpagroupId>
<artifactId>jpaartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>jpaname>
<description>JPA project for Spring Bootdescription>
<properties>
<java.version>1.8java.version>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
<spring-boot.version>2.3.0.RELEASEspring-boot.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-jdbcartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-jpaartifactId>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<scope>runtimescope>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
<exclusions>
<exclusion>
<groupId>org.junit.vintagegroupId>
<artifactId>junit-vintage-engineartifactId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.12version>
dependency>
dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-dependenciesartifactId>
<version>${spring-boot.version}version>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-compiler-pluginartifactId>
<configuration>
<source>1.8source>
<target>1.8target>
<encoding>UTF-8encoding>
configuration>
plugin>
<plugin>
<groupId>com.github.wvengengroupId>
<artifactId>proguard-maven-pluginartifactId>
<version>2.2.0version>
<executions>
<execution>
<phase>packagephase>
<goals>
<goal>proguardgoal>
goals>
execution>
executions>
<configuration>
<injar>${project.build.finalName}.jarinjar>
<outjar>${project.build.finalName}.jaroutjar>
<obfuscate>trueobfuscate>
<options>
<option>-target 1.8option>
<option>-dontshrinkoption>
<option>-dontoptimizeoption>
<option>-adaptclassstringsoption>
<option>-ignorewarnings
option>
<option>-keep class org.apache.logging.log4j.util.* { *; }option>
<option>-dontwarn org.apache.logging.log4j.util.**option>
<option>-keepattributes
Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,*Annotation*,EnclosingMethod
option>
<option>-keepclassmembers enum * { *; }option>
<option>-keepparameternamesoption>
<option>-keepclasseswithmembers public class * {
public static void main(java.lang.String[]);}
option>
<option>-dontnote javax.annotation.**option>
<option>-dontnote sun.applet.**option>
<option>-dontnote sun.tools.jar.**option>
<option>-dontnote org.apache.commons.logging.**option>
<option>-dontnote javax.inject.**option>
<option>-dontnote org.aopalliance.intercept.**option>
<option>-dontnote org.aopalliance.aop.**option>
<option>-dontnote org.apache.logging.log4j.**option>
<option>-keep class com.erbadagang.data.jpa.JpaApplicationoption>
<option>-keep class com.erbadagang.data.jpa.base.* {*;}option>
<option>-keep class com.erbadagang.data.jpa.entity.* {*;}option>
<option>-keep class com.erbadagang.data.jpa.model.* {*;}option>
<option>-keep class com.erbadagang.data.jpa.controller.* {*;}option>
<option>-keep interface * extends * { *; }option>
<option>-keepclassmembers class * {
@org.springframework.beans.factory.annotation.Autowired *;
@org.springframework.beans.factory.annotation.Value *;
}
option>
options>
<libs>
<lib>${java.home}/lib/rt.jarlib>
<lib>${java.home}/lib/jce.jarlib>
libs>
configuration>
<dependencies>
<dependency>
<groupId>net.sf.proguardgroupId>
<artifactId>proguard-baseartifactId>
<version>6.1.1version>
dependency>
dependencies>
plugin>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
<executions>
<execution>
<goals>
<goal>repackagegoal>
goals>
<configuration>
<mainClass>com.erbadagang.data.jpa.JpaApplicationmainClass>
configuration>
execution>
executions>
plugin>
plugins>
build>
project>