javaee加密部署项目通过tomcat使用自定义的classload解密

来源:互联网 发布:知乎大神侵权 编辑:程序博客网 时间:2024/06/15 17:19

参考文章:http://blog.itpub.net/29754888/viewspace-1220306/

如上述文章所说,继承tomcat的WebappClassLoader自定义自己的classload,并不适用于spring。

原因是spring加载类是用另外的方式来加载。

意思应该是是需要封装的jar代码中不能有spring的注解(依赖注入、控制器声明等等)


原理:

通过加密java代码的class文件,实现对源代码的保护,并通过自定义的classload文件来解密class文件,把类加载到项目中

自定义自己的classload,并重写findClass方法。类加载器通过调用findClass方法,寻找并加载类文件。

通过重写findClass方法,可以把预先加密好的class文件,解密后再加载到项目中

package generator;import java.io.BufferedReader;import java.io.ByteArrayOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStreamReader;import java.io.UnsupportedEncodingException;import java.security.InvalidKeyException;import java.security.NoSuchAlgorithmException;import java.util.ArrayList;import java.util.List;import javax.crypto.BadPaddingException;import javax.crypto.Cipher;import javax.crypto.IllegalBlockSizeException;import javax.crypto.NoSuchPaddingException;import javax.crypto.spec.SecretKeySpec;import org.apache.catalina.loader.WebappClassLoader;/** * 自定义的classloader 可以解密文件并加载 *  * @author uikoo9 */public class UClassLoader extends WebappClassLoader {/** * 算法 */private String algorithmStr="AES/ECB/PKCS5Padding";/** * key */private String keyStr="abcdefg123456789";/** * 默认构造器 *  * @throws Exception */public UClassLoader() {super();}/** * 默认构造器 *  * @param parent * @throws Exception */public UClassLoader(ClassLoader parent) {super(parent);}/* * (non-Javadoc) *  * @see * org.apache.catalina.loader.WebappClassLoader#findClass(java.lang.String) */public Class findClass(String name) throws ClassNotFoundException {if (name.contains("com.A")|| name.contains("com.B")|| name.contains("com.C")) {return findClassEncrypt(name);} else {return super.findClass(name);}}/** * 查找class *  * @param name * @return * @throws ClassNotFoundException */private Class findClassEncrypt(String name) throws ClassNotFoundException {byte[] classBytes = null;try {classBytes = loadClassBytesEncrypt(name);} catch (Exception e) {e.printStackTrace();}Class cl = defineClass(name, classBytes, 0, classBytes.length);if (cl == null) {System.out.println("找不到该类:" + name);throw new ClassNotFoundException(name);}return cl;}/** * 加载加密后的class字节流 *  * @param name * @return * @throws Exception */private byte[] loadClassBytesEncrypt(String name) throws Exception {// 获取当前文件路径// File directory = new File("");// String parentPath = directory.getAbsolutePath()+File.separator;String parentPath = "F:\\";List<String> basepath = new ArrayList<String>();basepath.add(parentPath + "A\\");// 项目物理地址basepath.add(parentPath + "B\\");// 项目物理地址basepath.add(parentPath + "C\\");// 项目物理地址String cname = null;File file = null;for (String path : basepath) {cname = path + name.replace('.', '\\') + ".cls";file = new File(cname);if (file.exists()) {break;}}if (file != null) {if (!file.exists()) {throw new Exception("File Not found:" + cname);}}FileInputStream in = new FileInputStream(cname);try {ByteArrayOutputStream buffer = new ByteArrayOutputStream();byte[] buf = new byte[1024 * 100];// 100KBint len = 0;while ((len = in.read(buf)) != -1) {buffer.write(buf, 0, len);}in.close();return decrypt(parseHexStr2Byte(new String(buffer.toByteArray())));} finally {in.close();}}/** * 解密 *  * @param content * @return */private byte[] decrypt(byte[] content) {try {byte[] keyBytes = this.keyStr.getBytes("utf-8");SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");Cipher cipher = Cipher.getInstance(this.algorithmStr);cipher.init(Cipher.DECRYPT_MODE, key);byte[] result = cipher.doFinal(content);return result;} catch (UnsupportedEncodingException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (NoSuchAlgorithmException e) {e.printStackTrace();} catch (NoSuchPaddingException e) {e.printStackTrace();} catch (InvalidKeyException e) {e.printStackTrace();} catch (IllegalBlockSizeException e) {e.printStackTrace();} catch (BadPaddingException e) {e.printStackTrace();}return null;}/** * 十六进制字符串转字节 *  * @param hexStr * @return */private byte[] parseHexStr2Byte(String hexStr) {if (hexStr.length() < 1)return null;byte[] result = new byte[hexStr.length() / 2];for (int i = 0; i < hexStr.length() / 2; i++) {int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);result[i] = (byte) (high * 16 + low);}return result;}}
在tomcat的content.xml文件中,配置自定义的classload为tomcat默认的classload

在<Content>中添加如下代码

<Loader loaderClass="generator.UClassLoader" delegate="true"></Loader>
指定环境上下文类加载为自定义的classload

注意:自定义的classload放在tomcat的lib下,并且文件夹层级结构需要跟包名一致generator/UClassLoader.class


大概步骤如下

1、对需要加密的class进行算法加密,本人是用AES加密

2、把加密后的class文件放到固定的地方,把项目中的对应class删除

3、修改context.xml的指定上下文类加载器为自定义加载器

4、启动tomcat



另外:如果不想自定义tomcat的classload,也可以自定义classload继承URLClassLoader

代码方式类似,也是通过重写findClass方法。编写好自定义classload后,在项目中实例化该类。

package classload;import java.io.BufferedInputStream;import java.io.ByteArrayOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.IOException;import java.io.UnsupportedEncodingException;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.net.MalformedURLException;import java.net.URL;import java.net.URLClassLoader;import java.security.InvalidKeyException;import java.security.NoSuchAlgorithmException;import java.util.ArrayList;import java.util.List;import javax.crypto.BadPaddingException;import javax.crypto.Cipher;import javax.crypto.IllegalBlockSizeException;import javax.crypto.NoSuchPaddingException;import javax.crypto.spec.SecretKeySpec;public class MyClassLoader extends URLClassLoader {/** * 算法 */private String algorithmStr="AES/ECB/PKCS5Padding";/** * key */private String keyStr="abcdefg123456789";    public MyClassLoader(URL[] urls){super(urls);}public MyClassLoader(URL[] urls, ClassLoader parent){super(urls,parent);}public static void main(String[] args) throws MalformedURLException {URL url = new File("a.jar").toURI().toURL();MyClassLoader classLoader = new MyClassLoader(new URL[]{url},Thread.currentThread().getContextClassLoader());//设置自定义classload为环境上下文类加载器Thread.currentThread().setContextClassLoader(classLoader);}public Class findClass(String name) throws ClassNotFoundException {if (name.contains("com.A")|| name.contains("com.B")|| name.contains("com.C")) {return findClassEncrypt(name);} else {return super.findClass(name);}}/** * 查找class *  * @param name * @return * @throws ClassNotFoundException */private Class findClassEncrypt(String name) throws ClassNotFoundException {byte[] classBytes = null;try {classBytes = loadClassBytesEncrypt(name);} catch (Exception e) {e.printStackTrace();}Class cl = defineClass(name, classBytes, 0, classBytes.length);if (cl == null) {System.out.println("找不到该类:" + name);throw new ClassNotFoundException(name);}return cl;}/** * 加载加密后的class字节流 *  * @param name * @return * @throws Exception */private byte[] loadClassBytesEncrypt(String name) throws Exception {// 获取当前文件路径// File directory = new File("");// String parentPath = directory.getAbsolutePath()+File.separator;String parentPath = "F:\\";List<String> basepath = new ArrayList<String>();basepath.add(parentPath + "A\\");// 项目物理地址basepath.add(parentPath + "B\\");// 项目物理地址basepath.add(parentPath + "C\\");// 项目物理地址String cname = null;File file = null;for (String path : basepath) {cname = path + name.replace('.', '\\') + ".cls";file = new File(cname);if (file.exists()) {break;}}if (file != null) {if (!file.exists()) {throw new Exception("File Not found:" + cname);}}FileInputStream in = new FileInputStream(cname);try {ByteArrayOutputStream buffer = new ByteArrayOutputStream();byte[] buf = new byte[1024 * 100];// 100KBint len = 0;while ((len = in.read(buf)) != -1) {buffer.write(buf, 0, len);}in.close();return decrypt(parseHexStr2Byte(new String(buffer.toByteArray())));} finally {in.close();}}/** * 解密 *  * @param content * @return */private byte[] decrypt(byte[] content) {try {byte[] keyBytes = this.keyStr.getBytes("utf-8");SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");Cipher cipher = Cipher.getInstance(this.algorithmStr);cipher.init(Cipher.DECRYPT_MODE, key);byte[] result = cipher.doFinal(content);return result;} catch (UnsupportedEncodingException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (NoSuchAlgorithmException e) {e.printStackTrace();} catch (NoSuchPaddingException e) {e.printStackTrace();} catch (InvalidKeyException e) {e.printStackTrace();} catch (IllegalBlockSizeException e) {e.printStackTrace();} catch (BadPaddingException e) {e.printStackTrace();}return null;}/** * 十六进制字符串转字节 *  * @param hexStr * @return */private byte[] parseHexStr2Byte(String hexStr) {if (hexStr.length() < 1)return null;byte[] result = new byte[hexStr.length() / 2];for (int i = 0; i < hexStr.length() / 2; i++) {int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);result[i] = (byte) (high * 16 + low);}return result;}}


项目中加载该类

URL url = new File("a.jar").toURI().toURL();MyClassLoader classLoader = new MyClassLoader(new URL[]{url},Thread.currentThread().getContextClassLoader());//设置自定义classload为环境上下文类加载器Thread.currentThread().setContextClassLoader(classLoader);

构造函数必须传URL对象参数进去,所以要随便指定一个jar。





原创粉丝点击