SpringBoot通過proguard-maven-plugin插件進行實際項目代碼混淆,實測可用


本文主要研究下如何使用proguard-maven-plugin插件混淆springboot代碼。工程代碼是實際跑在線上的Springboot2.x項目,踩過N個坑,最后實測成功。

先說貼出成功的配置

<build>
    <finalName>spring</finalName>
    <resources>
        <resource>
            <directory>${basedir}/src/main/java</directory>
            <includes>
                <include>**/*.xml</include>
            </includes>
        </resource>
        <resource>
            <directory>${basedir}/src/main/resources</directory>
            <filtering>true</filtering>
            <excludes>
                <exclude>**/application-*.yml</exclude>
            </excludes>
        </resource>
    </resources>
    <plugins>
        <!--代碼混淆-->
        <plugin>
            <groupId>com.github.wvengen</groupId>
            <artifactId>proguard-maven-plugin</artifactId>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals><goal>proguard</goal></goals>
                </execution>
            </executions>
            <configuration>
                <proguardVersion>6.0.3</proguardVersion>
                <injar>${project.build.finalName}.jar</injar>
                <!-- <injar>classes</injar> -->
                <outjar>${project.build.finalName}.jar</outjar>
                <obfuscate>true</obfuscate>
                <options>
                    <!--  ##默認是開啟的,這里關閉shrink,即不刪除沒有使用的類/成員-->
                    <option>-dontshrink</option>
                    <!-- ##默認是開啟的,這里關閉字節碼級別的優化-->
                    <option>-dontoptimize</option>
                    <!--##對於類成員的命名的混淆采取唯一策略-->
                    <option>-useuniqueclassmembernames</option>
                    <!--- 混淆類名之后,對使用Class.forName('className')之類的地方進行相應替代-->
                    <option>-adaptclassstrings </option>
                    <option>-ignorewarnings</option>
                    <!-- 混淆時不生成大小寫混合的類名,默認是可以大小寫混合-->
                    <option>-dontusemixedcaseclassnames</option>
                    <!-- This option will replace all strings in reflections method invocations with new class names.
                         For example, invokes Class.forName('className')-->
                    <!-- <option>-adaptclassstrings</option> -->
                    <!-- This option will save all original annotations and etc. Otherwise all we be removed from files.-->
                    <!-- 不混淆所有特殊的類-->
                    <option>-keepattributes Exceptions,InnerClasses,Signature,Deprecated,
                        SourceFile,LineNumberTable,*Annotation*,EnclosingMethod</option>
                    <!-- This option will save all original names in interfaces (without obfuscate).-->
                    <option>-keepnames interface **</option>
                    <!-- This option will save all original methods parameters in files defined in -keep sections,
                         otherwise all parameter names will be obfuscate.-->
                    <option>-keepparameternames</option>
                    <!-- <option>-libraryjars **</option> -->
                    <!-- This option will save all original class files (without obfuscate) but obfuscate all in domain package.-->
                    <!--<option>-keep class !com.slm.proguard.example.spring.boot.domain.** { *; }</option>-->
                    <option>-keep class !com.dsys.project.** { *; }</option>
                    <option>-keep class com.dsys.project.App { *; }</option>
                    <option>-keep class com.dsys.project.config.** { *; }</option>
                    <!--保留不然Mybatis報錯-->
                    <option>-keep class com.dsys.project.entity.** { *; }</option>
                    <option>-keep class com.dsys.project.utils.PageRes { *; }</option>
                    <option>-keep class com.dsys.project.controller.** { *; }</option>
                    <option>-keep class com.dsys.project.mp.controller.** { *; }</option>
                    <option>-keep class com.dsys.project.mp.config.** { *; }</option>
                    <option>-keep class com.dsys.project.dto.** { *; }</option>
                    <option>-keep class * implements java.io.Serializable </option>
                    <!-- This option will save all original class files (without obfuscate) in service package-->
                    <!--<option>-keep class com.slm.proguard.example.spring.boot.service { *; }</option>-->
                    <!-- This option will save all original interfaces files (without obfuscate) in all packages.-->
                    <option>-keep interface * extends * { *; }</option>
                    <!-- <option>-keep @org.springframework.stereotype.Service class *</option> -->
                    <!-- This option will save all original defined annotations in all class in all packages.-->
                    <option>-keepclassmembers class * {
                        <!-- @org.springframework.beans.factory.annotation.Autowired *; -->
                        @org.springframework.beans.factory.annotation.Value *;
                        }
                    </option>
                </options>
                <libs>
                    <!-- Include main JAVA library required.-->
                    <lib>${java.home}/lib/rt.jar</lib>
                </libs>
            </configuration>
            <dependencies>
                <dependency>
                    <groupId>net.sf.proguard</groupId>
                    <artifactId>proguard-base</artifactId>
                    <version>6.2.2</version>
                </dependency>
            </dependencies>
        </plugin>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <executions>
                <execution>
                    <!-- <phase>none</phase> -->
                    <goals>
                        <goal>repackage</goal>
                    </goals>
                    <configuration>
                        <mainClass>com.dsys.project.App</mainClass>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

主要的坑,springboot項目配置注意項

啟動類不能混淆

//混淆會把Bean的名稱重復,這里要求SpringBoot生成唯一的BeanName
@SpringBootApplication
@MapperScan("com.dsys.project.dao")
@ComponentScan("com.dsys")
@ServletComponentScan("com.dsys")
@EnableCaching
@EnableAsync
public class App {
    public static class CustomGenerator implements BeanNameGenerator {

        @Override
        public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
            return definition.getBeanClassName();
        }
    }

    /***
     * 由於proguard混淆貌似不能指定在basePackages下面類名混淆后唯一,不同包名經常有a.class,b.class,c.class之類重復的類名,因此spring容器初始化bean的時候會報錯。
     *慶幸的是,我們可以通過改變spring的bean的命名策略來解決這個問題,把包名帶上,就唯一了
     * @param args
     */
    public static void main(String[] args) {
        new SpringApplicationBuilder(App.class)
                .beanNameGenerator(new CustomGenerator())
                .run(args);
    }
}

實體類一定要保留

解釋:這里的實體類包括各種Entity,Dto等。保留的原因有:
1. Mybatis的XML的ResultType需要實體類的全路徑
2. Jackson需要序列化,字段混淆前端會找不到

Controller一定要保留

解釋:Controller混淆了前端找不到請求路徑,模板引擎例如thymeleaf找不到路徑

SpringBoot JavaConfig配置不能混淆

//解釋:例如下面的JavaConfig配置,混淆后配置出錯
@Data
@ConfigurationProperties(prefix = "wx.mp")
public class WxMpProperties {
    private List<MpConfig> configs;

    @Data
    public static class MpConfig {
        private String appId;
  }
}

其他配置參考以上的注釋,其他照抄修改成自己的項目對應路徑即可,使用JD-GUI反編譯查看效果。
file


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM