Flink 代码混淆
Posted 文大侠
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flink 代码混淆相关的知识,希望对你有一定的参考价值。
原理
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>
几点注意说明
- 这里打包默认会生成proguard_map.txt和proguard_seed.txt,前者表示具体的混淆列表,后者表示对应命中proguad的keep规则的列表
- 混淆后的java包如果报异常,默认我们看到的堆栈中各种名称是混淆后的,如果需要看到对应的混淆前的堆栈,需要利用proguard_map.txt反混淆,具体过程参考文档
https://www.guardsquare.com/manual/tools/retrace - 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
以上是关于Flink 代码混淆的主要内容,如果未能解决你的问题,请参考以下文章
译文《Apache Flink官方文档》 Apache Flink介绍
[Essay] Apache Flink:十分可靠,一分不差