代码混淆,不再让生产环境代码裸奔

Posted 天山一剑卓不凡

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了代码混淆,不再让生产环境代码裸奔相关的知识,希望对你有一定的参考价值。

概述

代码混淆,是将计算机程序的代码,转换成一种功能上等价,但是难于阅读和理解的形式的行为。将代码中的各种元素,如变量,函数,类的名字改写成无意义的名字。比如改写成单个字母,或是简短的无意义字母组合,甚至改写成“__”这样的符号,使得阅读的人无法根据名字猜测其用途。重写代码中的部分逻辑,将其变成功能上等价,但是更难理解的形式。比如将改写成while循环,将循环改写成递归,精简中间变量,等等。打乱代码的格式。比如删除空格,将多行代码挤到一行中,或者将一行代码断成多行等等。

在实际开发中,项目源码jar包或者war包放置服务器上进行部署,如果有人将安装包拉取下来,进行反编译是可以还原代码的,所以需要进行代码混淆措施。

方案

采用ProGuard实现。

ProGuard 是一个开源的,最流行的 Java 字节码和 android 应用程序优化器和代码混淆器。

官网:https://www.guardsquare.com/proguard

SpringBoot中使用ProGuard插件

步骤

  1. 搭建SpringBoot工程,导入ProGuard插件

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.3</version>
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>com.github.wvengen</groupId>
                <artifactId>proguard-maven-plugin</artifactId>
                <version>2.6.0</version>
                <executions>
                    <!-- 执行mvn的package命令时候,会执行proguard-->
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>proguard</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <!-- 就是输入Jar的名称,我们要知道,代码混淆其实是将一个原始的jar,生成一个混淆后的jar,那么就会有输入输出。 -->
                    <injar>$project.build.finalName.jar</injar>
                    <!-- 输出jar名称,输入输出jar同名的时候就是覆盖,也是比较常用的配置。 -->
                    <outjar>$project.build.finalName.jar</outjar>
                    <!-- 是否混淆 默认是true -->
                    <obfuscate>true</obfuscate>
                    <!-- 配置一个文件,通常叫做proguard.cfg,该文件主要是配置options选项,也就是说使用proguard.cfg那么options下的所有内容都可以移到proguard.cfg中 -->
                    <proguardInclude>$project.basedir/proguard.cfg</proguardInclude>
                    <!-- 额外的jar包,通常是项目编译所需要的jar -->
                    <libs>
                        <lib>$java.home/lib/rt.jar</lib>
                        <lib>$java.home/lib/jce.jar</lib>
                        <lib>$java.home/lib/jsse.jar</lib>
                    </libs>
                    <!-- 对输入jar进行过滤比如,如下配置就是对META-INFO文件不处理。 -->
                    <inLibsFilter>!META-INF/**,!META-INF/versions/9/**.class</inLibsFilter>
                    <!-- 这是输出路径配置,但是要注意这个路径必须要包括injar标签填写的jar -->
                    <outputDirectory>$project.basedir/target</outputDirectory>
                    <!--配置混淆的一些细节选项,比如哪些类不需要混淆,哪些需要混淆-->
                    <options>
                        <!-- 可以在此处写option标签配置,上面使用了proguardInclude,引用配置好的混淆规则 -->
                    </options>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                        <configuration>
                            <mainClass>com.qfedu.proguard.ProguardApplication</mainClass>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

2、创建proguard.cfg文件

设置混淆规则

#指定Java的版本
-target 1.8
#proguard会对代码进行优化压缩,删除从未使用的类或者类成员变量等
-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 * 
                        @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
-keep public class com.qfedu.proguard.ProguardApplication 
        public static void main(java.lang.String[]);
    

Keep选项概述对比

作用范围

保持所指定类、成员

所指定类、成员在压缩阶段没有被删除,才能被保持

类和类成员

-keep

-keepnames

仅类成员

-keepclassmembers

-keepclassmembernames

类和类成员(前提是成员都存在)

-keepclasseswithmembers

-keepclasseswithmembernames

  1. 执行打包命令

控制台可以看到执行混淆命令

查看生成的jar包

4、使用反编译工具查看源码

对比源码和混淆之后代码

完整混淆规则可以参考官网文档。

以上是关于代码混淆,不再让生产环境代码裸奔的主要内容,如果未能解决你的问题,请参考以下文章

五大原则让你的代码不再受bug的困扰

大数据时代,如何让个人信息不再“裸奔”?

解决生产环境js无法调试问题

maven混淆Java代码

你的生产环境还在“裸奔”吗?给服务器上个监控吧

Android混淆