java springBoot项目代码加密总结

         项目需要向外出售,涉及到版权问题需要进行代码加密。两周时间最终实现了对核心的一个package内的代码进行加密。还未实现对带有spring注解的类进行加密,但是以现在的技术积淀应该没有什么大的问题就可以将加密移植到springBoot源码之中,这个如果有的话后期再更新吧。

        java加密很难,是因为源码编译后的字节码保留的源码信息是在太多导致了很容易被反编译。但是如果不是这样的话java也实现不了跨平台。所以加密的核心或者本质就是避免在程序装载到虚拟机之前保持字节码的不可见。加密思路当然就是将字节码使用AES等算法加密之后,解密并装载类的部分放到运行的虚拟机之中动态执行。并且解密这一部分用C/C++进行编写,在java中使用JNI技术调用。这样就成功将java的反编译难度提升到了反编译C的难度了。

     知识一:ClassLoader的原理,这个自行查资料学习,但是需要注意的是。如果要加密的类比较复杂,比如一个类A中含有普通内部类、抽象内部类、讲台内部类、匿名内部类、内部接口。这就是加载难点所在。java编译之后的类A其实会生成多个.class文件,如果要使用自己的ClassLoader进行加载的话,必须控制好加载顺序。

      ClassLoader的字节码加载顺序如下:

            1、接口(普通接口或者内部接口)以及抽象类(普通抽象类或者内部抽象类)

            2、静态内部类 

            3、其他类(普通类,匿名内部类,普通内部类,枚举)

具体如何实现自己想办法吧,我是写了段代码去使用正则表达式,通过遍历对比源码和字节码文件名进行了字节码文件的筛选,并排好顺序。

     知识二:字节码文件存储的格式问题。我是将所有需要加密的字节码文件按照上面的加载顺序排好顺序之后顺序写入到了一个文件中去的,然后将这个大的字节码文件进行加密。需要注意的是,读取字节码之后需要转换成Hex格式存储到其他文件中,然后在JVM中解密之后再将Hex格式的字节码转换回字节码。如果直接将获取到的自己么byte[]写入到文件的话会丢失数据,导致字节码的损坏。

     知识三:由于很多类字节码文件被放到了一个加密文件中,它是在项目中被动态加载进JVM的,所以类在项目中是不存在的,这个时候就知道基于接口的编程是多么重要了。没办法,尽量将这个包最外层暴露在外的方法使用接口暴露,然后在项目中可以获取到动态加载的Clas对象,使用反射生成相应的对象。我在项目中写了一个ClassesManager,它保存了动态加载之后的>即类名和类反射的Map,然后向外提供getObject(String className)方法。

     知识四:C语言解密部分,这个地方最好是实现使用JNI技术实现C的调用,C里面所做的是将加密文件解密然后向外提供类似getByte的方法,将解密后的字节码文件返回给java,当然了,AES密码是明文写入C的,所以这个地方C源码的保存很重要。因为C不是硬件无关的,所以你需要经常在不同的服务器下编译C源码,这时候一定要记得保护好C源码。这个地方不好的地方当然也就是由于C的介入,导致了项目的硬件相关性,这个地方现在我确实也没有更好的办法来解决。有个需要注意的是,之一java的兼容性,java是向前兼容的。有些jdk8的字节码是不能被jdk7运行的。所以....

   知识五:ClassLoader会引起的类转换异常。自定义的所有ClassLoader的父ClassLoader都是AppClassLoader,也就是说自定义的ClassLoader都是同级的,即使是像这种情况:自定义n个ClassLoader,ClassLoader1加载ClassLoader2,classLoader2加载classLoader3........,这n个classLoader的父classLoader都是AppClassLoader,他们依然是同级的,这样的话如果每个自定义ClassLoader

都加载一个class A的话,当获取classLoader1获取到classLoader2中加载的A对象然后强转为自己加载的A的接口时就会出现类转换异常,因为class在JVM的唯一性和加载它的ClassLoader有关。这时候可以手动指定ClassLoader2的父ClassLoader为ClasssLoader1,ClassLoader3的父ClassLoader为ClasssLoader2,这样的话就没问题了。他们就属于一个Class家族了,并且有了严格的等级关系,不属于同级的了。如果继承ClassLoader的话,是不能完成父ClassLoader的指定的,需要继承URLClassLoader才行,并且new URLClassLoader(url[] urls,ClassLoader parent)中的urls可以指定为{},但是不要用null,会有空指针异常。


    掌握了上述几点基本上就没问题了,至于要加密整个SpringBoot的话,当然是可以的,只不过我时间有限。有个思路就是去修改SpringBoot的源码,修改他的ClassLoader。应该不难,毕竟难点都在上面了。good luck to you!

你可能感兴趣的:(java,编程相关,Web开发)