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

作者:郭嘉

邮箱:[email protected]

博客: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:\Users\Administrator

直接运行

直接运行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可以使用,结果如下图所示:

时间: 2024-11-11 03:53:34

【Java 安全技术探索之路系列:J2SE安全架构】之二:安全管理器的相关文章

【Java 安全技术探索之路系列:J2SE安全架构】之六:安全管理工具

作者:郭嘉 邮箱:[email protected] 博客:http://blog.csdn.net/allenwells github:https://github.com/AllenWell [Java 安全技术探索之路系列:J2SE安全架构]章节列表 [Java安全技术探索之路系列:J2SE安全架构]之一:J2SE安全架构开篇 [Java 安全技术探索之路系列:J2SE安全架构]之五:类加载器 [Java 安全技术探索之路系列:J2SE安全架构]之六:安全管理工具 作为J2SE复合包的一部

【Java安全技术探索之路系列:Java可扩展安全架构】之四:JCA(三):JCA编程模型

作者:郭嘉 邮箱:[email protected] 博客:http://blog.csdn.net/allenwells github:https://github.com/AllenWell 一 消息摘要 使用MD5计算消息摘要 try { MessageDigest md5 = MessageDigest.getInstance("MD5"); byte[] testdata = { 1, 2, 3, 4, 5 }; md5.update(testdata); byte[] my

【Java Swing探索之路系列】之一:Java Swing开篇

作者:郭嘉 邮箱:[email protected] 博客:http://blog.csdn.net/allenwells github:https://github.com/AllenWell Java Swing是一个用于开发Java图形界面应用程序的开发工具包,它一抽象窗口工具包(Abstract Window Toolkit)为基础,是跨平台应用程序可以使用任何可插拔的外观风格. 一 Swing特性 多样化的Ul组件:包括从技钮.分隔窗格到表格的所有组件. 可插式外观样式:允许任何使用S

【Java Swing探索之路系列】之二:Java Swing布局面板组件

作者:郭嘉 邮箱:[email protected] 博客:http://blog.csdn.net/allenwells github:https://github.com/AllenWell 面板指的是容器,即中间容器类,可以将基本组件放置在其中,组成丰富多彩的用户界面. 一 JPanel 在JPanel的使用中,有一个双缓冲的概念,这个技术旨在改进频繁变化的组件显示效果.可以在JPanel初始化的时候进行定义如下所示: 举例 展示如何使用JPanel中间容器类. import javax.

【Java Swing探索之路系列】之三:Java Swing布局管理器组件

作者:郭嘉 邮箱:[email protected] 博客:http://blog.csdn.net/allenwells github:https://github.com/AllenWell 一 BorderLayout BorderLayout是一种简单的布局策略,可以将其看作一个组件.它把容器分为东.南.西.北.中5个区域,每个组件将占据某个区域.而 这5个区域分别被命名为NORTH, WEST, EAST, CENTER, SOUTH,它们都被定义为静态 常量.静态常量可以直接引用,如

【Java 虚拟机探索之路系列】:JIT编译器

作者:郭嘉 邮箱:[email protected] 博客:http://blog.csdn.net/allenwells github:https://github.com/AllenWell 为什么会Java虚拟机会同时存在解释器和编译器呢? 这是为了兼顾启动效率和执行效率两个方面.Java程序最初是通过解释器进行解释执行的,当虚拟机返现某个方法或代码块的运行特别频繁时,就会把这段代码标记为热点代码,为了提供热点代码的执行效率,在运行时,虚拟机就会把这些代码编译成与本地平台相关的机器码,并进

java之jvm学习笔记六(实践写自己的安全管理器)

安全管理器SecurityManager里设计的内容实在是非常的庞大,它的核心方法就是checkPerssiom这个方法里又调用AccessController的checkPerssiom方法,访问控制器AccessController的栈检查机制又遍历整个PerssiomCollection来判断具体拥有什么权限一旦发现栈中一个权限不允许的时候抛出异常否则简单的返回,这个过程实际上比我的描述要复杂得多,这里我只是简单的一句带过,因为这里涉及到很多比较后面的知识点. 下面来尝试一下写一个非常简单

java安全沙箱(四)之安全管理器及Java API

java是一种类型安全的语言,它有四类称为安全沙箱机制的安全机制来保证语言的安全性,这四类安全沙箱分别是: 类加载体系 .class文件检验器 内置于Java虚拟机(及语言)的安全特性 ??安全管理器及Java API?? 本篇博客主要介绍"类安全管理器及Java API"的基本原理,如需了解其它几类安全机制可以通过上面的博客链接进入查看. 简介 java安全沙箱的前三类保证了jvm所运行程序的完整性,使得jvm不会因为运行有漏洞或恶意的代码而导致出现不可预期的状态.而第四类沙箱模型是

java之jvm学习笔记六-十二(实践写自己的安全管理器)(jar包的代码认证和签名) (实践对jar包的代码签名) (策略文件)(策略和保护域) (访问控制器) (访问控制器的栈校验机制) (jvm基本结构)

java之jvm学习笔记六(实践写自己的安全管理器) 安全管理器SecurityManager里设计的内容实在是非常的庞大,它的核心方法就是checkPerssiom这个方法里又调用 AccessController的checkPerssiom方法,访问控制器AccessController的栈检查机制又遍历整个 PerssiomCollection来判断具体拥有什么权限一旦发现栈中一个权限不允许的时候抛出异常否则简单的返回,这个过程实际上比我的描述要复杂 得多,这里我只是简单的一句带过,因为这