一般来说我们在写Java程序时都会使用Maven(或Gradle)做依赖集成。这过程中Maven(或Gradle)作为编译黑盒,输入源码而输出字节码。但我们也知道Java程序是可以通过反编译工具看到源码,这就很尴尬了,倘若你的团队拥有的核心代码不想被别人转译盗取,但代码管理规范并没有在信息安全上做得“滴水不漏”,这时即使没有源码授权,破译获取也是分分钟的事情。

若真出现这种情况,那么代码混淆器能够帮到你。在不做入侵式代码加密的前提下,网上有两个比较成熟的解决方案。一个是ProGuard,另一个是Allatori。

ProGuard开源且能直接整合到项目,但加密效果简单且配置复杂。个人认为学习曲线比较陡峭且对已有的自动化运维体系整合难度较大因此弃用了这个方案。Allatori虽然收费,但配置上使用上都比较简单,再加上强大的加密算法应该是商业使用的首选吧。最最重要的是它虽然付费授权但也不贵,能花钱解决的尽量花钱解决就完事了。

使用Allatori做代码加密的思路也比较简单:

  1. 开发人员只需关注自己的开发内容并提交到Gitlab(或SVN)版本库;
  2. 在使用Jenkins(或其他自动化工具)进行代码打包时,设置打包的“前置步骤”,运维人员写好脚本将Allatori的配置文件加入到项目目录的指定位置;
  3. 之后就能够通过Maven(或Gradle)进行打包(package)。注意,这里将部署(deploy)步骤后置不能直接使用mvn deploy将代码直接上传私库(这里涉及到一个命名的问题);
  4. 若涉及到组件jar包的加密,则还需要将加密后的jar包的名字进行修改,让其保持与其他pom依赖中编写的命名一致;
  5. 在Jenkins中添加“后置步骤”,通过命令将修改名字后的jar包上传到私库;

通过以上的步骤就能够将Allatori整合到以Jenkins为基础的自动化运维体系中,但由于我本机没有部署Jenkins,只能给各位演示一下Allatori的加密效果。

demo中使用到的Allatori工具将采用网上提供的破解版本,本人是基于学习的态度使用该破解版并已经在下载后24小时内删除,只保留以下使用记录。请各位在商用时支持正版。

【Java】Allatori代码加密_Allatori

如上图所示,首先先将demo源码包(config-center-0.0.1.jar),allatori加密程序(allatori.jar)和allatori配置(allatori.xml)放在同一文件夹内并执行以下代码:

java -Xms128m -Xmx512m -jar allatori.jar allatori.xml

请注意,这里一定要设置一个比较大的JVM对参数,不然在加密过程中会存在“假死”状态。

【Java】Allatori代码加密_Jenkins_02

执行完成后会生成一个加密包,如下图:

【Java】Allatori代码加密_Jenkins_03

我们使用反编译工具对加密前后的jar包进行对比展示

【Java】Allatori代码加密_Allatori_04

上面是代码加密前

【Java】Allatori代码加密_Jenkins_05

这个是代码加密后,是不是好像能看懂又好像看不懂...这个是正常现象。要做成以上效果还需要这样配置信息,如下图:

<config>
<!-- 输入包和输出包配置 -->
<input>
<jar in = "config-center-0.0.1.jar" out = "config-center-0.0.1-safe.jar" />
</input>
<ignore-classes>
<!-- 排除指定路径 -->
<class template = "class xx.yyy.*.dao.*"/>
<class template = "class xx.yyy.*.model.*"/>
<class template = "class xx.yyy.*.vo.*"/>
<!-- 排除启动类 -->
<class template = "class xx.yyy.ConfigApplication"/>
<!-- 排除springboot依赖文件(springboot构建的项目需要排除,否则业务程序会报错) -->
<class template = "class *springframework*"/>
<class template = "class *java*"/>
<class template = "class *org*"/>
<class template = "class *com*"/>
<class template = "class *alibaba*"/>
<class template = "class *persistence*"/>
</ignore-classes>
<!-- 保留名称 -->
<keep-names>
<class access = "protected+">
<field access = "protected+" />
<method access = "protected+" />
</class>
</keep-names>
<!-- 水印 -->
<watermark key="secure-key-to-extract-watermark" value="@Copyright (c) by yyy Co., Ltd."/>
<!-- 随机字符加密 -->
<property name="random-seed" value="6a5919ab 77d66eda 8150aa02 894eae66 97695714"/>
<!-- 加密记录 -->
<property name="log-file" value="log.xml"/>
<!-- 保留参数名称 -->
<property name="local-variables-naming" value="keep-parameters"/>
<!-- 字符串加密 -->
<property name="string-encryption" value="maximum"/>
<property name="string-encryption-type" value="strong"/>
<property name="string-encryption-version" value="v4"/>
<!-- 广泛流混淆 -->
<property name="control-flow-obfuscation" value="enable"/>
<property name="extensive-flow-obfuscation" value="maximum" apply2class="class xx.yyy.*.rest.*"/>
<property name="extensive-flow-obfuscation" value="maximum" apply2class="class xx.yyy.*.service.**"/>
<!-- 更新资源名称 -->
<property name="update-resource-names" value="enable"/>
<property name="update-resource-contents" value="enable"/>
<!-- 行数混淆 -->
<property name="line-numbers" value="obfuscate"/>
<!-- 泛型混淆 -->
<property name="generics" value="remove"/>
<!-- 成员重新排序 -->
<property name="member-reorder" value="random"/>
<!-- 数据jar压缩等级 -->
<property name="output-jar-compression-level" value="9"/>
<!-- 删除toString标签 -->
<property name="remove-toString" value="enable"/>
</config>

以上注释已经讲得相当清晰这里就不再叙述,关于配置的详情还可以查看官网地址:​http://www.allatori.com/doc.html​