• 【Java 安全技术探索之路系列:J2SE安全架构】之二:安全管理器


    作者:郭嘉
    邮箱:allenwells@163.com
    博客:http://blog.csdn.net/allenwells
    github:https://github.com/AllenWell

    一 安全管理器的功能

    安全管理器是一个同意程序实现安全策略的类,它会在执行阶段检查须要保护的资源的訪问权限及其它规定的操作权限。保护系统免受恶意操作攻击。以达到系统的安全策略。

    安全管理器负责检查的操作主要包括以下几个:

    • 创建一个新的类载入器
    • 退出虚拟机
    • 使用反射訪问还有一个类的成员
    • 訪问本地连接
    • 打开socket连接
    • 启动打印作业
    • 訪问系统剪贴板
    • 訪问AWT事件队列
    • 打开一个顶层窗体

    注意:在执行Java应用程序时,默认的设置是不安装安全管理器的,这样全部的操作都是同意的,

    安全管理器的工作流程例如以下图所看到的:

    这里写图片描写叙述

    一 安全管理器的使用

    1.1 获取安全管理器

    
    Security security = System.getSecurityManager();
    

    1.2 启动安全管理器

    1.2.1 命令行启动

    java -Djava.security.manager class_name

    1.2.2 程序启动

    在启动安全管理器时能够通过-Djava.security.policy选项来指定安全策略文件。

    假设没有指定策略文件的路径,那么安全管理器将使用默认的安全策略文件,它位于%JAVA_HOME%/jre/lib/security文件夹以下的java.policy。

    注意

    • =表示这个策略文件将和默认的策略文件一同发挥作用。
    • ==表示仅仅使用这个策略文件。

    policy文件包括了多个grant语句,每个grant描写叙述某些代码拥有某些操作的权限。在启动安全管理器时会依据policy文件生成一个Policy对象,不论什么时候一个应用程序仅仅能有一个Policy对象

    SecurityManager sm=new SecurityManager();
    System.setSecurityManager(sm);
    

    默认的%JAVA_HOME%/jre/lib/security/java.policy文件内容例如以下所看到的:

    // Standard extensions get all permissions by default
    
    grant codeBase "file:${{java.ext.dirs}}/*" {
            permission java.security.AllPermission;
    };
    
    // default permissions granted to all domains
    
    grant {
            // Allows any thread to stop itself using the java.lang.Thread.stop()
            // method that takes no argument.
            // Note that this permission is granted by default only to remain
            // backwards compatible.
            // It is strongly recommended that you either remove this permission
            // from this policy file or further restrict it to code sources
            // that you specify, because Thread.stop() is potentially unsafe.
            // See the API specification of java.lang.Thread.stop() for more
            // information.
            permission java.lang.RuntimePermission "stopThread";
    
            // allows anyone to listen on dynamic ports
            permission java.net.SocketPermission "localhost:0", "listen";
    
            // "standard" properies that can be read by anyone
    
            permission java.util.PropertyPermission "java.version", "read";
            permission java.util.PropertyPermission "java.vendor", "read";
            permission java.util.PropertyPermission "java.vendor.url", "read";
            permission java.util.PropertyPermission "java.class.version", "read";
            permission java.util.PropertyPermission "os.name", "read";
            permission java.util.PropertyPermission "os.version", "read";
            permission java.util.PropertyPermission "os.arch", "read";
            permission java.util.PropertyPermission "file.separator", "read";
            permission java.util.PropertyPermission "path.separator", "read";
            permission java.util.PropertyPermission "line.separator", "read";
    
            permission java.util.PropertyPermission "java.specification.version", "read";
            permission java.util.PropertyPermission "java.specification.vendor", "read";
            permission java.util.PropertyPermission "java.specification.name", "read";
    
            permission java.util.PropertyPermission "java.vm.specification.version", "read";
            permission java.util.PropertyPermission "java.vm.specification.vendor", "read";
            permission java.util.PropertyPermission "java.vm.specification.name", "read";
            permission java.util.PropertyPermission "java.vm.version", "read";
            permission java.util.PropertyPermission "java.vm.vendor", "read";
            permission java.util.PropertyPermission "java.vm.name", "read";
    };

    1.3 关闭安全管理器

    SecurityManager sm=System.getSecurityManager();
    if(sm!=null)
    {
        System.setSecurityManager(null);
    }

    以上代码仅仅有在位于{JDK_HOME}/jre/lib/security文件夹下或者其它指定文件夹下的java.policy文件里指定了一个权限才会生效。

    该权限是:

    permission java.lang.RuntimePermission"setSecurityManager";

    1.4 安全管理器检查

    security.checkXXX(...);

    检查完毕后,成功则安全管理器返回。失败则安全管理器抛出SecurityException,注意该约定唯一的例外是checkTopLevelWindow。它返回boolean值

    1.5 安全管理器权限检查

    安全管理器中全部其它check()方法的默认实现都是调用SecurityManager.checkPermission()方法来确定线程是否具有执行所请求的操作的权限。

    仅仅带有单个权限參数的checkPermission()方法总是在当前执行的线程上下文中执行安全检查。

    假设在给定的上下文进行检查须要在不同的上下文中进行,能够使用Java提供的包括上下文參数的getSecurityContext()方法和checkPermission()方法,例如以下所看到的:

    Object context = null;
    SecurityManager sm = System.getSecurityManager();
    if(sm != null)
    {
        context = sm.getSecurityContext();//该方法返回当前调用上下文的一个快照
        sm.checkPermission(permission, context);//该方法使用一个上下文对象,以及依据该上下文(不是当前执行线程的上下文)作出訪问决策的权限。
    }

    权限分为以下几个类别:

    • 文件
    • 套接字
    • 网络
    • 安全性
    • 执行时
    • 属性
    • AWT
    • 反射
    • 可序列化

    相应的权限类为:

    • java.io.FilePermission
    • java.net.SocketPermission
    • java.net.NetPermission
    • java.security.SecurityPermission
    • java.lang.RuntimePermission
    • java.util.PropertyPermission
    • java.awt.AWTPermission
    • java.lang.reflect
    • ReflectPermission
    • java.io.SerializablePermission

    整个权限类的层次结构例如以下图所看到的:

    这里写图片描写叙述

    以下写一个样例来演示一下自己定义安全管理器的使用。

    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    public class SecurityManagerDemo
    {
         public static void main(String[] args) throws FileNotFoundException 
        {
             System.out.println("SecurityManager: " + System.getSecurityManager());
             FileInputStream fis = new FileInputStream("C:\Users\Administrator\my.txt");
             System.out.println(System.getProperty("file.encoding"));
        }
    }

    注意:my.txt是已经存在的文件,须要在你的文件夹创建,这里的文件夹是C:UsersAdministrator

    直接执行

    直接执行SecurityManagerDemo,相当于没有启动安全管理器,SecurityManager打印出来为null,且能正确读取protect.txt文件跟file.encoding属性。例如以下图所看到的:

    这里写图片描写叙述

    加入启动參数执行

    加入启动參数

    -Djava.security.manager -Djava.security.policy=C:\Users\Administrator\my.policy//自己定义策略文件
    

    指定-Djava.security.manager參数,此时SecurityManager打印出来为不为null,my.policy里面并没有做不论什么授权。所以在读取文件的时就抛出AccessControlException异常,例如以下图所看到的:

    这里写图片描写叙述

    创建my.policy,并写入以下grant:

    grant {
    permission java.io.FilePermission "C:\Users\Administrator\my.txt", "read";
    permission java.util.PropertyPermission "file.encoding", "read";
    };
    

    此时能够正确读取。例如以下图所看到的:

    这里写图片描写叙述

    三 实现自己定义的安全管理器

    实现自己定义的安全管理器一般分为两步:

    1. 创建一个SecurityManager子类,依据须要重写一些方法。
    2. 依据应用程序代码的权限须要配置策略文件。

    以下写一个样例来演示一下自己定义安全管理器的使用:

    自己定义类MySecurityManager继承于SecurityManager,重写了checkRead()方法。

    public class MySecurityManager extends SecurityManager 
    {  
    
        @Override  
        public void checkRead(String file) 
        {  
            //super.checkRead(file, context);  
            if (file.endsWith("not")) 
            {
                throw new SecurityException("你没有读取的本文件的权限");    
            }           
        }  
    
    }  
    

    写个測试类MySecurityManagerDemo观察MySecurityManager是否实用。

    import java.io.FileInputStream;  
    import java.io.IOException;  
    
    public class MySecurityManagerDemo 
    {  
        public static void main(String[] args)
        {  
            System.setSecurityManager(new MySecurityManager());  
            try 
            {  
                FileInputStream fis = new FileInputStream("not");  
                System.out.println(fis.read());  
            } 
            catch (IOException e) 
            {  
                e.printStackTrace();  
            }  
          }  
    }  

    执行完毕后,输出打印“你没有读取的本文件的权限”。说明MySecurityManager能够使用。结果例如以下图所看到的:

    这里写图片描写叙述

  • 相关阅读:
    Java性能小技巧
    使用Gitolite搭建Gitserver
    refresh的停车场(栈和队列的STL)
    BZOJ 2005 NOI2010 能量採集 数论+容斥原理
    PHP第四课 了解经常使用的函数
    JavaScript实现对象数组按不同字段排序
    android之Context对各种服务的管理
    程序员应该阅读的非编程类书籍有哪些?
    是男人就下100层【第五层】——换肤版2048游戏
    是男人就下100层【第四层】——Crazy贪吃蛇(3)
  • 原文地址:https://www.cnblogs.com/wzjhoutai/p/7159625.html
Copyright © 2020-2023  润新知