現在大部分的j2ee程式都沒有一個好的保護辦法,很傳統的辦法就是混淆編譯,但是如果使用混淆邊以後,可能導致jsp中的代碼不能正常運行。
其實有個好的辦法就是使用定製ClassLoader來load一些關鍵的類,使用定製的classload來裝載類的話,就可以對關鍵的類加密後在解密後就可以了。
如果只這樣的話可能還存在漏洞,就是定製ClassLoader沒有加密,如果ClassLoader反編譯後就可能得到你的類了,我們第一步所做的就成了徒勞。有沒有好的辦法解決這個問題呢?其實也有,就是修改java.exe,自己控制java.exe裝載定製的classloader具體的辦法可以參照如何有效保護JAVA程式。
另外還有一個問題就是,在tomcat,weblogic,websphere等應用伺服器中怎樣能保證他們使用定製的classloader來load我加密的類呢?一般應用伺服器是不提供這個外部classloader這個功能的。要解決這個問題就是使用factory設計模式,介面,實作類別和工廠類,在工廠類中擷取介面執行個體化類的時候不用直接new,而是首先調用執行個體化定製的classloader,接著調用定製classloader的load方法裝載類。
程式碼段如下:
//MyClassLoader.java
package com.test.classload;
import java.util.jar.*;
import java.io.*;
public final class MyClassLoader extends ClassLoader {
private static JarFile jar = null;
public MyClassLoader() {
}
public Class findClass(String name) throws java.lang.ClassNotFoundException {
Class clasz = null;
clasz = findLoadedClass(name);
if(clasz!=null){
return clasz;
}
if(jar==null)
try {
String dir = System.getProperty("user.dir");
String fileName = dir + File.separator +"test.jar";
jar = new JarFile(fileName);
}
catch (IOException ex) {
throw new ClassNotFoundException(name);
}
String className = name.replace('.','/');
className = className + ".class";
JarEntry entry = jar.getJarEntry(className);
try {
InputStream is = jar.getInputStream(entry);
int len = is.available();
byte[] cls = new byte[len];
is.read(cls,0,len);
clasz = defineClass(name,cls,0,len);
if(clasz==null){
clasz = findSystemClass(name);
}
}
catch (IOException ex) {
throw new ClassNotFoundException(name);
}
return clasz;
}
}
//MyClassLoader.java
package com.test.classload;
import java.util.jar.*;
import java.io.*;
public final class MyClassLoader extends ClassLoader {
private static JarFile jar = null;
public MyClassLoader() {
}
public Class findClass(String name) throws java.lang.ClassNotFoundException {
Class clasz = null;
clasz = findLoadedClass(name);
if(clasz!=null){
return clasz;
}
if(jar==null)
try {
String dir = System.getProperty("user.dir");
String fileName = dir + File.separator +"test.jar";
jar = new JarFile(fileName);
}
catch (IOException ex) {
throw new ClassNotFoundException(name);
}
String className = name.replace('.','/');
className = className + ".class";
JarEntry entry = jar.getJarEntry(className);
try {
InputStream is = jar.getInputStream(entry);
int len = is.available();
byte[] cls = new byte[len];
is.read(cls,0,len);
clasz = defineClass(name,cls,0,len);
if(clasz==null){
clasz = findSystemClass(name);
}
}
catch (IOException ex) {
throw new ClassNotFoundException(name);
}
return clasz;
}
}
//TestDAO.java
package com.test.classload;
public interface TestDAO {
public String getName();
}
//TestDAOImp.java
package com.test.classload;
public class TestDAOImp implements TestDAO {
public TestDAOImp() {
}
public String getName() {
return "方見華";
}
}