八、类加载器2——实战

来源:互联网 发布:秒杀抢购软件 编辑:程序博客网 时间:2024/05/14 04:39


如果我们用java平台,也许在安全上我们进了一小步,这一小步对于程序员和平台管理员有一些要求,产生一些额外的工作量,这些日常的工作正如下所介绍



一、让你的程序,或者j2ee运行安全管理器

启动程序VM变量:

-Djava.security.manager -Djava.security.policy=D:/java.policy


我们可以指定多个安全文件.policy文件。只需要修改.security文件配置即可。




二、程序员可以定义自己的类加载器


package ClassLoader;import java.io.FilePermission;import java.net.URL;import java.net.URLClassLoader;import java.security.CodeSource;import java.security.PermissionCollection;import java.security.Permissions;import java.util.HashMap;public class myClassLoader extends URLClassLoader {public myClassLoader(URL[] urls) {super(urls);}public final synchronized Class loadClass(String name, boolean resolve)throws ClassNotFoundException {// 要有包的访问权限SecurityManager sm = System.getSecurityManager();if (sm != null) {int i = name.lastIndexOf('.');if (i != -1) {sm.checkPackageAccess(name.substring(0, i));}}return super.loadClass(name, resolve);}protected Class findClass(final String name) throws ClassNotFoundException {// 定义包下class的权限SecurityManager sm = System.getSecurityManager();if (sm != null) {int i = name.lastIndexOf('.');if (i != -1) {sm.checkPackageDefinition(name.substring(0, i));}}return super.findClass(name);}protected PermissionCollection getPermissions(CodeSource codesource) {// Use all the standard permissions, plus allow the code to// exit the VM.//默认由父加载器设置类的权限,URLClassLoader将会沿用java策略//PermissionCollection pc = super.getPermissions(codesource);//pc.add(new RuntimePermission("exitVM"));//pc.add(pc);//完全由自己的类加载器指定类权限FilePermission fp = new FilePermission("E:/-", "read,execute");FilePermission fp1 = new FilePermission("D:/-", "read,execute");Permissions ps = new Permissions();ps.add(fp);ps.add(fp1);return ps;}}

以上是我们自定义的类加载器,由他加载的类没有其他的权限,但是有访问D盘 、E盘文件的权限。


我们用他加载一个类,这个类主要用于访问文件,但是我们只希望加载进来的类访问E、D盘的文件,这个类加载器很好的满足了安全要求

一步一步看看!!

先定义一个接口,这个接口主要是用于访问文件,他有一个远程(第三方)的实现类

注意:请注意类加载的层次关系,层次关系不仅安全,对接口的使用也是很有用处的,父类加载器载入接口,子类就能载入接口的实现了,所以接口在应用部署上应该优先考虑,标准的接口应该尽量使用java核心包中接口。


package ClassLoader;public interface AccessFileInterface {public void readFile(String fileName);}

这个接口我们和myClassLoader放在同一个包中,由应用的加载器加载。


接着,我们在远程创建一个文件访问类,实现上面的接口

我们把接口copy到另外一个项目,并实现如下类

package classloadtest;import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStream;import ClassLoader.AccessFileInterface;public class AccessFile implements AccessFileInterface{public void readFile(String fileName){File file = new File(fileName);        InputStream in = null;        try {            System.out.println("以字节为单位读取文件内容,一次读一个字节:");            // 一次读一个字节            in = new FileInputStream(file);            int tempbyte;            while ((tempbyte = in.read()) != -1) {                System.out.write(tempbyte);            }            in.close();        } catch (IOException e) {            e.printStackTrace();            return;        }        try {            System.out.println("以字节为单位读取文件内容,一次读多个字节:");            // 一次读多个字节            byte[] tempbytes = new byte[100];            int byteread = 0;            in = new FileInputStream(fileName);            this.showAvailableBytes(in);            // 读入多个字节到字节数组中,byteread为一次读入的字节数            while ((byteread = in.read(tempbytes)) != -1) {                System.out.write(tempbytes, 0, byteread);            }        } catch (Exception e1) {            e1.printStackTrace();        } finally {            if (in != null) {                try {                    in.close();                } catch (IOException e1) {                }            }        }}    /**     * 显示输入流中还剩的字节数     */    private void showAvailableBytes(InputStream in) {        try {            System.out.println("当前字节输入流中的字节数为:" + in.available());        } catch (IOException e) {            e.printStackTrace();        }    }        public static void main(String[] args) {    AccessFile a = new AccessFile();    a.readFile("D:\\testread.txt");}}


这个类实现了接口,并不能访问任何的文件,(因为java默认的配置策略赋予了他最大的权限——默认是没文件权限的),此时运行程序会抛出不能访问文件的异常,

如下的异常:


以字节为单位读取文件内容,一次读一个字节:Exception in thread "main" java.security.AccessControlException: access denied ("java.io.FilePermission" "D:\testread.txt" "read")at java.security.AccessControlContext.checkPermission(AccessControlContext.java:372)at java.security.AccessController.checkPermission(AccessController.java:559)at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)at java.lang.SecurityManager.checkRead(SecurityManager.java:888)at java.io.FileInputStream.<init>(FileInputStream.java:135)at classloadtest.AccessFile.readFile(AccessFile.java:17)at classloadtest.AccessFile.main(AccessFile.java:66)




为了让这个类有权访问文件,我们可以让myclassloader加载它

接下来,我们做一个应用,用myclassloader加载这个文件访问类

package ClassLoader;import java.net.MalformedURLException;import java.net.URL;import java.net.URLClassLoader;import java.util.Date;public class test1 {public static void main(String[] args) {URL[] urls = new URL[1];try {urls[0] = new URL("file:/E:/workspace_20140601/classloadtest/bin/");} catch (MalformedURLException e) {// TODO Auto-generated catch blocke.printStackTrace();}try {//long t_s = (new Date()).getTime();URLClassLoader ucl = new myClassLoader(urls);//ucl.loadClass("classloadtest.AccessFile");//ucl.loadClass("classloadtest.AccessFile1");//long t_s2 = (new Date()).getTime();//System.out.println(t_s-t_s2);Class<?> c = ucl.loadClass("classloadtest.AccessFile");AccessFileInterface acc = (AccessFileInterface)(c.newInstance());acc.readFile("d:/testread.txt");//long t_s3 = (new Date()).getTime();//System.out.println(t_s-t_s3);Class<?> c1 = ucl.loadClass("classloadtest.AccessFile1");AccessFileInterface acc1= (AccessFileInterface)(c1.newInstance());acc1.readFile("e:/testread1.txt");//long t_s4 = (new Date()).getTime();//System.out.println(t_s-t_s4);} catch (ClassNotFoundException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}}}


这个应用使用myClassLoader加载Accessfile类, 并给这个类相应的权限-----d、e盘所有的访问权限,

现在这个类能够访问所有的d、e盘下的文件了,没有异常发生了,另外由这个加载器加载的其他类都有这个权限了。


可以说,这个类加载器的所有URL资源被加载后,都会得到相应的文件访问权限,除非这个资源路径被父加载器覆盖。

另外,要注意,类加载赋予类权限的代码是特权代码。也许这就是漏洞哦,没有绝对的安全,就像你信任你的朋友,但是朋友也可能会坑害你一样,人为因素才是安全的伦理。


所以,我们最好是只读取签名的jar,提供完善的代码源,这样就能设定——谁签名的jar有多大的权限,这样我们能在平台上更方便引用第三放的类库,并设置安全了,虽然不能做到绝对安全,但是如果大家都有共同的利益所在,估计是不会让原子弹提前爆发的。






0 0
原创粉丝点击