SecurityManager
是一个允许应用实现一种安全策略的类。应用在执行一个安全或敏感的操作之前,可以明确此操作是否在一个安全的上下文中被执行。
一、 启停安全管理器
1.1 启用
-
系统启动开启
JVM参数:-Djava.security.manager
当运行一个程序,可以指定JVM命令-Djava.security.manager
开启SecurityManager
功能,这是打开SecurityManager
最常见的方式。
可以使用-Djava.security.policy
指定策略文件路径。 -
程序手动开启
// 创建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 策略准则
在启用安全管理器的时候,配置遵循以下基本原则
- 没有配置的权限,表示没权限
- 只能配置允许权限,没有禁止权限可以配置
- 同一种权限可多次配置,取并集
- 统一资源的多种权限可用逗号分割
默认配置文件解释
第一部分授权:授权基于路径在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 方法摘要
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)