1. 程式人生 > 實用技巧 >java、springboot使用proguard混淆程式碼

java、springboot使用proguard混淆程式碼

1.情景展示

  我的需求是:為了將專案部署到機器上時,既不影響專案的正常執行,又可以做到降低專案原始碼(class檔案)的可讀性,其主要目的是為了防盜。

  一般情況下是用不到混淆器的,但是實際生活中往往存在這樣的問題或需求,比方說:由於時間緊迫,兩家企業被迫聯合共同上線一個產品,現在是雖是合作關係,他們又可以相互取締,同樣的市場,蛋糕就這麼大,時間長了難免互生嫌隙,所以為了保護各自產品被竊取,就需要防盜神器proguard了。

2.proguard簡介

ProGuard 是一個免費的 Java類檔案的壓縮,優化,混餚器。它刪除沒有用的類,欄位,方法與屬性。使位元組碼最大程度地優化,使用簡短且無意義的名字來重新命名類、欄位和方法 。eclipse已經把Proguard整合在一起了。

  吐槽:但說句實在話,proguard雖然降低了程式碼的可讀性,但是,仍是能夠讀懂的,只是費點勁罷了。正所謂:防君子不防小人。

3.proguard教程

  第一步:maven配置(pom.xml)

<!--構建工具-->
<build>
    <!--自定義打包後的專案名稱
    可以無視預設的打包名稱規則:${artifactId}-${version}-->
    <finalName>bill</finalName>
    <plugins>
        <!--maven編譯外掛-->
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <!--二選一-->
            <version>${spring.version}</version>
            <!--<version>2.3.1.RELEASE</version>-->
        </plugin>
        <!--java混淆器外掛-->
        <plugin>
            <groupId>com.github.wvengen</groupId>
            <artifactId>proguard-maven-plugin</artifactId>
            <version>2.3.1</version>
            <executions>
                <execution>
                    <!-- 混淆時刻:這裡是打包的時候混淆 -->
                    <phase>package</phase>
                    <goals>
                        <!-- 使用外掛的什麼功能: 混淆-->
                        <goal>proguard</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <proguardVersion>${proguard.version}</proguardVersion>
                <!--<proguardVersion>6.2.2</proguardVersion>-->
                <!-- 是否混淆-->
                <obfuscate>true</obfuscate>
                <!--關鍵:引入配置檔案,這裡換成你的配置檔案所在路徑,一般情況下就是把proguard.cfg放到這個目錄-->
                <proguardInclude>${project.basedir}/src/main/resources/proguard.cfg</proguardInclude>
                <!-- 混淆時需要引用的java庫,這些庫的類不會做混淆 -->
                <libs>
                    <lib>${java.home}/lib/rt.jar</lib>
                    <lib>${java.home}/lib/jce.jar</lib>
                </libs>

                <!--當<injar></injar>的值為:classes時,可以結合該標籤使用,作用:相關混淆配置只為指定目錄下的class檔案起效-->
                <!--<inFilter>com/marydon/**</inFilter>-->
                <!-- 需要做混淆的jar或class目錄,也就是:選擇對什麼東西進行載入-->
                <injar>classes</injar>
                <!--<injar>${project.build.finalName}.jar</injar>-->

                <!--class 混淆後輸出的jar包,說明:這個輸出格式可有可無,下面會講 -->
                <outjar>${project.build.finalName}-pd.jar</outjar>
                <!-- 輸出目錄 -->
                <outputDirectory>${project.build.directory}</outputDirectory>
            </configuration>
            <dependencies>
                <dependency>
                    <groupId>net.sf.proguard</groupId>
                    <artifactId>proguard-base</artifactId>
                    <version>${proguard.version}</version>
                    <!--<version>6.2.2</version>-->
                    <scope>runtime</scope>
                </dependency>
            </dependencies>
        </plugin>
    </plugins>
 </build>

  這裡需要注意的一點是:build標籤需要在dependencies下方

  第二步:外掛下載

  先不要proguard.cfg檔案怎麼寫,搞定這個外掛才能繼續往下走,不然就是浪費時間,即使你將配置檔案寫好,離開了這個外掛,要配置檔案有啥用?

  為了搞定最新版的外掛,浪費了我不少時間,下面科普一下,如果你引入以上配置檔案後,proguard外掛下載成功,就可以跳過這一步了。

  上面這個外掛,明確的告訴你:阿里雲maven中央倉庫有!!!

  如果下載失敗,說明:該專案使用的maven中央倉庫不是阿里雲的,怎麼辦?

  很簡單,不用去該maven下面的settings.xml,直接在專案中引入即可。

 <!--配置專案的jar包倉庫-->
<repositories>
    <!--阿里雲倉庫,id=central,會覆蓋掉setting.xml中配置的中央倉庫-->
    <repository>
        <id>central</id>
        <name>central maven</name>
        <url>https://maven.aliyun.com/repository/central</url>
        <!--<url>http://maven.aliyun.com/nexus/content/groups/public/</url>-->
    </repository>
    <!--maven官網-->
    <repository>
        <id>public</id>
        <name>public maven</name>
        <url>https://mvnrepository.com</url>
    </repository>
</repositories>

  這樣,倉庫配置僅對本專案生效,也不會影響到其它專案對於settings.xml的依賴。

  這裡需要注意的一點是:repositories標籤需要在dependencies上方

  點選右側maven視圖裡的這個按鈕,網路較好的情況下,很快就下載完成了。

  如果外掛不再報錯,基本上就成了

  如果該外掛下載不成功,就沒有繼續進行下去的必要了,等搞定再往下看。

  第三步:proguard.cfg配置檔案

  新建proguard.cfg檔案,並將其放到src/main/resources目錄下

# Proguard配置項
# JDK目標版本1.8
-target 1.8
# 預設是開啟的,這裡關閉shrink,即不刪除沒有使用的類/成員(刪除註釋、未被引用程式碼)
-dontshrink
# 預設是開啟的,這裡關閉位元組碼級別的優化(變更程式碼實現邏輯)
-dontoptimize
# 忽略打包時的警告資訊
-ignorewarnings
# 不跳過非公用類檔案及成員
-dontskipnonpubliclibraryclasses
-dontskipnonpubliclibraryclassmembers
-dontusemixedcaseclassnames
# 優化時允許訪問並修改有修飾符的類和類的成員
-allowaccessmodification
# 混淆類名之後,對使用Class.forName('className')之類的地方進行相應替代
-adaptclassstrings
# 不混淆所有包名,Spring配置中有大量固定寫法的包名
-keeppackagenames
# 確定統一的混淆類的成員名稱來增加混淆:一個類中的成員不使用重複的命名,如Student類混淆後不能出現a屬性和a方法。
-useuniqueclassmembernames
# 不混淆所有特殊的類:對異常、註解資訊在runtime予以保留,不然影響springboot啟動
-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,LocalVariable*Table,*Annotation*,Synthetic,EnclosingMethod
# 保留介面類名(兩種方式:二選一)
-keepnames interface **
#-keep interface * extends * { *; }

# This option will save all original methods parameters in files defined in -keep sections, otherwise all parameter names will be obfuscate.
#-keepparameternames
#-keepdirectories
-keepclassmembers class * {
	@org.springframework.beans.factory.annotation.Autowired *;
	@org.springframework.beans.factory.annotation.Service *;
	@org.springframework.beans.factory.annotation.Value *;
	@org.springframework.web.bind.annotation.PostMapping *;
    @org.springframework.web.bind.annotation.DeleteMapping *;
    @org.springframework.web.bind.annotation.RestController *;
    @javax.annotation.Resource *;
	}

-keep class * implements java.io.Serializable { *; }
-keep class * implements org.springframework.boot.CommandLineRunner { *; }
# 保留列舉類的兩種方式(二選一)
#-keepclassmembers enum  * {
#    public static **[] values();
#    public static ** valueOf(java.lang.String);
#}
-keepclassmembers enum * { *; }
# 不混淆啟動類的main方法
-keep
	class com.marydon.bill.BillApplication {
    	public static void main(java.lang.String[]);
    }
# 保留程式入口(springboot專案的話,需要保留啟動類)
#-keep @org.springframework.boot.autoconfigure.SpringBootApplication class * {*;}
-keep class com.marydon.bill.SpringBootStartApplication { *; }
# dao 保留全部類及類成員,方法命名也不能變,因為與xml檔案做了關聯
-keep class com.marydon.bill.service.dao.** { *; }
# 不混淆所有的set/get方法,畢竟專案中使用的部分第三方框架(例如Shiro)會用到大量的set/get對映
-keepclassmembers public class * {void set*(***);*** get*();}
# 不對包類的類名進行混淆,但對類中的屬性和方法混淆
# 不混淆包下的所有類名,且類中的方法和屬性也不混淆

# 混淆指定包下的類   此處需要更改
-keep class !com.marydon.service.** { *; }
#-keep class !com.marydon.controller.**,!com.marydon.*.service.** {
#    <fields>;
#    <methods>;
#}
# 無視跳過警告  因為修改程式碼的過程程式檢測到有些檔案不能更改就會報警告導致失敗   如果對自己寫的程式碼比較有信心的話可以直接無視
# 不顯示警告資訊,如果顯示則會出現Error無法完成混淆!
-dontwarn **

  第四步:打包    

  使用maven外掛打包,開啟maven檢視,找到package,進行打包即可。

  打包成功日誌

  成功後,target目錄下會多出三個檔案

  bill-pd.jar,就是專案混淆後的jar包(

  也就是說:混淆後的程式碼會被proguard外掛單獨打成一個jar包,與bill.jar的主要區別就是:前者是帶有混淆的class檔案,後者是正常的class檔案

  這裡,講一下前面在pom.xml中配置的<outjar>${project.build.finalName}-pd.jar</outjar>標籤,這個標籤可有可無。

  如果去掉指定混淆檔案的輸出格式,打包後會是什麼樣的呢?

  區別在於:原來的bill-pd.jar變成了classes_proguard_base目錄

  裡面的內容沒有區別。

  第五步:injar與outjar

  這兩個標籤如果不配合好,效率將會大打折扣,而且還容易出錯。由上面我們知道,

  injar:是在外掛混淆的源目錄,也就是,混淆前的程式碼來源,它有兩種表現形式:第一種是class目錄,第二種是${project.build.finalName}.jar;

  outjar:外掛執行混淆完畢後,將要輸出的檔案打包成什麼樣的格式,這裡僅支援jar包,不支援war包,injar標籤也一樣;如果不宣告該標籤的話,將會預設生成classes_proguard_base目錄。

  第六步:部署專案

  方式一:部署jar包

  編譯源目錄格式使用:<injar>${project.build.finalName}.jar</injar>

  輸出目錄格式使用:<outjar>${project.build.finalName}-pd.jar</outjar>

  這樣,即使沒有前後端分離,我們也可以確保bill-pd.jar包含的是專案的完整程式碼,可以拿出直接使用

  方式二:部署war包

  編譯源目錄格式使用:<injar>classes</injar>

  輸出目錄格式使用:刪除<outjar></outjar>標籤

  打包標籤設定成war:<outjar>war</outjar>

  將專案打成war包後,用壓縮軟體開啟,依次開啟WEB-INF/classes目錄,刪掉,再將生成的混淆檔案裡的class檔案複製進去即可。

   

寫在最後

  哪位大佬如若發現文章存在紕漏之處或需要補充更多內容,歡迎留言!!!

相關推薦: