Flink 代码混淆

本文介绍了如何使用Proguard对Java代码进行混淆,特别是在Flink场景下的应用。重点讨论了混淆的目的、Proguard的配置以及在maven中的使用,包括混淆规则的设置以确保Flink作业的序列化和Scala兼容性。同时提到了混淆后堆栈跟踪的处理以及增量混淆的管理。最后,还探讨了在混淆后如何结合maven-shade-plugin进行依赖包的处理。
摘要由CSDN通过智能技术生成

原理

Java 默认编译完成,很容易反编译出源码逻辑
混淆本质上就是对于生成的class文件中敏感的部分替换,包括包名、类名、类成员变量、类成员函数、函数参数等

最常用的java混淆就是proguard混淆
对应仓库 https://github.com/Guardsquare/proguard

Flink代码混淆

这样指的是混淆提交给flink运行的业务代码,不是混淆flink的框架代码
通常可能是scala+java的混编代码,有大量的序列化逻辑存在,因此需要注意proguard的配置
通常的java工程和spring的混淆配置不适用

maven配置

借助maven插件 https://github.com/wvengen/proguard-maven-plugin
完成编译完成自动混淆

增加如下配置

<properties>
<proguard-maven-plugin.version>2.5.1</proguard-maven-plugin.version>
    <proguard.version>7.1.1</proguard.version>
</properties>

<!--proguard混淆插件 在build中指定插件-->
<plugin>
    <groupId>com.github.wvengen</groupId>
    <artifactId>proguard-maven-plugin</artifactId>
    <version>${proguard-maven-plugin.version}</version>
    <executions>
        <execution>
            <!--打包的时候开始混淆-->
            <phase>package</phase>
            <goals>
                <goal>proguard</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <!-- 开启混淆 配置proguard的版本和对应配置文件 -->
        <obfuscate>true</obfuscate>
        <proguardVersion>${proguard.version}</proguardVersion>
        <proguardInclude>${basedir}/script/obfuscate/proguard.cfg</proguardInclude>

        <!-- 输入输出和对应依赖jar -->
        <!-- -injars -->
        <injar>${project.build.finalName}.jar</injar>
        <!-- -outjars -->
        <outjar>${project.build.finalName}.jar</outjar>
        <!-- -libraryjars = libs+project dependencies -->
        <libs>
            <lib>${java.home}/lib/rt.jar</lib>
            <lib>${java.home}/lib/jsse.jar</lib>
            <lib>${java.home}/lib/jce.jar</lib>
        </libs>

        <!--增量迭代-->
        <applyMappingFile>${basedir}/script/obfuscate/proguard_map.txt</applyMappingFile>

        <!--指定定输出新旧元素名的对照表的文件-->
        <mappingFileName>proguard_map.txt</mappingFileName>
        <!--配置匹配的类或者类成员的详细列表-->
        <seedFileName>proguard_seed.txt</seedFileName>

        <!-- 其它proguard命令配置 -->
        <options>
            <!--默认开启,不做收缩(删除注释、未被引用代码)-->
            <option>-dontshrink</option>
            <!--默认是开启的,这里关闭字节码级别的优化-->
            <option>-dontoptimize</option>

            <!--对于类成员的命名的混淆采取唯一策略,用于mapping文件增量更新-->
            <option>-useuniqueclassmembernames</option>
            <!--混淆时不生成大小写混合的类名,默认是可以大小写混合,保证windows等大小写敏感系统正常-->
            <option>-dontusemixedcaseclassnames </option>

            <!--忽略note消息-->
            <option>-dontnote</option>
        </options>

    </configuration>
    <dependencies>
        <dependency>
            <groupId>com.guardsquare</groupId>
            <artifactId>proguard-base</artifactId>
            <version>${proguard.version}</version>
            <scope>runtime</scope>
        </dependency>
    </dependencies>
</plugin>

几点注意说明

  1. 这里打包默认会生成proguard_map.txt和proguard_seed.txt,前者表示具体的混淆列表,后者表示对应命中proguad的keep规则的列表
  2. 混淆后的java包如果报异常,默认我们看到的堆栈中各种名称是混淆后的,如果需要看到对应的混淆前的堆栈,需要利用proguard_map.txt反混淆,具体过程参考文档
    https://www.guardsquare.com/manual/tools/retrace
  3. proguard_map.txt管理需要注意,每次编译后丢失了就很难找回,默认混淆是随机混淆,每次编译混淆结果都不一样。
    一种方式是每次编译的时候都把当前包对应的proguard_map.txt保存起来,比如cicd中上传到指定位置
    另一种是这里的applyMappingFile,配置的是增量map,每次编译时指定映射,这样同一样的代码,只要指相同的proguard_map.txt,混淆结果相同。这里需要初始化时创建这个目录,默认为空文件,每次生成完成后手动替换新的proguard_map.txt到这里的目录

shade混编处理

代码中通常会遇到,需要把所有依赖包一起提交运行的需求,通常会使用maven-shade-plugin插件。
所以如上的配置需要保证混淆前后的包名不变,这样只需要再混淆插件后增加maven-shade-plugin插件,即可基于前一步的混淆结果继续打依赖包。

proguard配置

主要是要保证scala的运行和flink的序列化正常,当前所用配置供参考

-verbose

# 只混淆公司的包
-keep class !com.xxx.xx.**

# scala 参考 https://github.com/Guardsquare/proguard/blob/v7.2.0/examples/standalone/scala.pro

-renamesourcefileattribute SourceFile
-keepattributes Signature,Exceptions,*Annotation*,
                InnerClasses,PermittedSubclasses,EnclosingMethod,
                Deprecated,SourceFile,LineNumberTable

# Preserve all public applications.

-keepclasseswithmembers public class * {
    public static void main(java.lang.String[]);
}

# Preserve some classes and class members that are accessed by means of
# introspection.

-keep class * implements org.xml.sax.EntityResolver

-keepclassmembers class * {
    ** MODULE$;
}

# Preserve all native method names and the names of their classes.

-keepclasseswithmembernames,includedescriptorclasses class * {
    native <methods>;
}

# Preserve the special static methods that are required in all enumeration
# classes.

-keepclassmembers,allowoptimization enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

# Explicitly preserve all serialization members. The Serializable interface
# is only a marker interface, so it wouldn't save them.
# You can comment this out if your application doesn't use serialization.
# If your code contains serializable classes that have to be backward
# compatible, please refer to the manual.

-keepnames class * implements java.io.Serializable

-keepclassmembers class * implements java.io.Serializable {
    static final long serialVersionUID;
    private static final java.io.ObjectStreamField[] serialPersistentFields;
    !static !transient <fields>;
    private void writeObject(java.io.ObjectOutputStream);
    private void readObject(java.io.ObjectInputStream);
    java.lang.Object writeReplace();
    java.lang.Object readResolve();
}

# 对于flink 需要处理序列化lambda 问题
# 参考 https://www.guardsquare.com/manual/configuration/examples#serializable
-keepclassmembers class * {
    private static synthetic java.lang.Object $deserializeLambda$(java.lang.invoke.SerializedLambda);
}

-keepclassmembernames class * {
    private static synthetic *** lambda$*(...);
}

参考

proguard 官方配置

  • https://www.guardsquare.com/manual/configuration/usage
  • https://www.jianshu.com/p/60e82aafcfd0

proguard maven插件配置

  • https://wvengen.github.io/proguard-maven-plugin/
  • https://langyastudio.blog.csdn.net/article/details/123783160
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值