Java之SecurityManager安全管理器

SecurityManager是一个允许应用实现一种安全策略的类。应用在执行一个安全或敏感的操作之前,可以明确此操作是否在一个安全的上下文中被执行。

一、 启停安全管理器

1.1 启用

  1. 系统启动开启
    JVM参数-Djava.security.manager
    当运行一个程序,可以指定JVM命令-Djava.security.manager开启SecurityManager功能,这是打开SecurityManager最常见的方式。
    可以使用-Djava.security.policy指定策略文件路径。

  2. 程序手动开启

    // 创建SecurityManager实例
    SecurityManager securityManager = new SecurityManager();
    // 设置启动
    System.setSecurityManager(securityManager);
    

注意:你可能会认为,使用System.setProperty(“java.security.manager”)也能打开SecurityManager,但这种方式并不会生效。原因就是,系统属性是在当JVM启动时进行检查的,在JVM完全启动之后,程序手动设置的系统属性,并不能奏效,因为已经不在对系统属性进行检查了。

1.2 关闭

如果想要关闭SecurityManager,该怎么做? 下面的代码能做到吗?

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

注意:只有在位于${JDK_HOME}/jre/lib/security目录下或其他指定目录下的java.policy文件中指定了一个权限(permission java.lang.RuntimePermission "setSecurityManager")才会奏效。

二、安全策略

2.1 默认配置

默认的安全管理器配置文件是$JAVA_HOME/jre/lib/security/java.policy,即当未指定配置文件时,默认使用该配置文件。

// 授权基于路径在"file:${{java.ext.dirs}}/*"下的class和jar包,所有权限。
grant codeBase "file:${{java.ext.dirs}}/*" {
        permission java.security.AllPermission;
};
grant {
        // permission: 许可
        // java.lang.RuntimePermission: 校验权限类
        // stopThread: 校验项
        permission java.lang.RuntimePermission "stopThread";
        
        // 允许监听端口
        permission java.net.SocketPermission "localhost:0", "listen";

        // permission for standard RMI registry port
        // 允许监听标准RMI注册表端口
        permission java.net.SocketPermission "localhost:1099", "listen";
        
        // 允许读取通过Sytem.getProperty("java.version")读取属性值
        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";
};

2.2 策略准则

在启用安全管理器的时候,配置遵循以下基本原则

  1. 没有配置的权限,表示没权限
  2. 只能配置允许权限,没有禁止权限可以配置
  3. 同一种权限可多次配置,取并集
  4. 统一资源的多种权限可用逗号分割

默认配置文件解释
第一部分授权:授权基于路径在file:${{java.ext.dirs}}的class和jar包所有权限。

grant codeBase "file:${{java.ext.dirs}}/*" {
    permission java.security.AllPermission;
};

第二部分授权:这是细粒度的授权,对某些资源的操作进行授权。

grant { 
    permission java.lang.RuntimePermission "stopThread";
}

补充:当批量配置的时候(如:第一部分授权),有三种模式

  • directory/:表示directory目录下的所有.class文件,不包括.jar文件
  • directory/*:表示directory目录下的所有的.class.jar文件
  • directory/-:表示directory目录下的所有的.class.jar文件,包括子目录

可以通过${}来引用系统属性,如: “file:${{java.ext.dirs}}/*”

三、SecurityManager

3.1 概要描述

SecurityManager类包含许多以check开头命名的方法。java库中的各种方法在执行一些敏感的操作时,可以调用这些方法。

SecurityManager security = System.getSecurityManager();
if (security != null) {
	security.checkXXX(argument);
}

SecurityManager通过抛出异常(SecurityException)阻止没有权限操作的完成,唯一的例外就是checkTopLevelWindow方法返回boolean值,但是已经弃用。

Java2 SDK v1.2开始,SecurityManager中其他check方法底层是调用SecurityManager#checkPermission方法来确定调用线程是否具有执行请求操作的权限。

注意,只有一个权限参数的checkPermission方法总是在当前执行线程的上下文中执行安全检查。 有时,需要在特定上下文中进行安全检查,那么需要执行checkPermission(Permission perm, Object context))完成。 SecurityManager提供了包含上下文参数的getSecurityContext方法返回当前调用上下文的“快照”(默认实现返回一个AccessControlContext对象)。

AccessControlContext acc = null;
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
	acc = sm.getSecurityContext(); 
}

其中,权限类别包括:文件,套接字,网络,安全,运行时,属性,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 。

3.2 方法摘要

SecurityManager方法摘要

3.3 使用

策略配置

...

grant {
	...

    // permission java.util.PropertyPermission "java.version", "read";

    ...
};


Java实现

public class SecurityMain {
    public static void main(String[] args) {
        SecurityManager securityManager = new SecurityManager();
        System.setSecurityManager(securityManager);
        securityManager.getSecurityContext();
        
        securityManager.checkPropertyAccess("java.version");
    }
}

执行结果

Exception in thread "main" java.security.AccessControlException: 
    access denied ("java.util.PropertyPermission" "java.version" "read")
	at java.security.AccessControlContext.checkPermission(AccessControlContext.java:472)
	at java.security.AccessController.checkPermission(AccessController.java:886)
	at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
	at java.lang.SecurityManager.checkPropertyAccess(SecurityManager.java:1294)
	at pojo.SecurityMain.main(SecurityMain.java:7)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值