java安全管理器SecurityManager

中国人最喜欢访问的网站
只要注册ofo就送你10块钱,还等什么,快来注册吧

问题的提出

阅读源码中关于SecurityManager的代码

1
2
3
4
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkWrite(name);
}

在本机运行正常,在服务器运行报错权限错误:

1
2
3
4
5
6
Exception in thread "main" java.security.AccessControlException: access denied (java.lang.RuntimePermission createSecurityManager)
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:374)
at java.security.AccessController.checkPermission(AccessController.java:549)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:532)
at java.lang.SecurityManager.<init>(SecurityManager.java:282)
...

为了彻底明白这些情况,需要研究一下SecurityManager

SecurityManager应用场景

当运行未知的Java程序(可能有恶意代码(删除系统文件、重启系统等))时,为了防止恶意代码对系统产生影响,需要对运行的代码的权限进行控制,这时就需要启用Java安全管理器。

管理器配置文件

默认配置文件

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// 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
-Djava.security.manager

指定配置文件的位置:

1
-Djava.security.manager -Djava.security.policy="E:/java.policy"

编码方式启用

1
System.setSecurityManager(new SecurityManager());

参数启用本质上也是通过编码启用,不过参数启用灵活(sun.misc.Launcher):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
String str = System.getProperty("java.security.manager");
if (str != null)
{
SecurityManager localSecurityManager = null;
if (("".equals(str)) || ("default".equals(str))) {
localSecurityManager = new SecurityManager();
} else {
try
{
localSecurityManager = (SecurityManager)this.loader.loadClass(str).newInstance();
}
catch (IllegalAccessException localIllegalAccessException) {}catch (InstantiationException localInstantiationException) {}catch (ClassNotFoundException localClassNotFoundException) {}catch (ClassCastException localClassCastException) {}
}
if (localSecurityManager != null) {
System.setSecurityManager(localSecurityManager);
} else {
throw new InternalError("Could not create SecurityManager: " + str);
}
}

会创建一个默认的SecurityManager

配置文件解析

配置基本原则

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

  • 没有配置的权限表示没有
  • 只能配置有什么权限,不能配置禁止做什么
  • 同一种权限可多次配置,取并集。
  • 统一资源的多种权限可用逗号分割。

默认配置文件解释

第一部分授权:

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

授权位于”file:$/*”下的class和jar包所有权限。

第二部分授权:

1
2
3
4
grant {
permission java.lang.RuntimePermission "stopThread";
……
}

这是细粒度的授权,对某些资源进行授权。RuntimePermission的可授权操作(stopThread仅仅是其中的一个)如下(可查看javadoc):

权限目标名称 权限所允许的操作 允许此权限所带来的风险
createClassLoader 创建类加载器 授予该权限极其危险。能够实例化自己的类加载器的恶意应用程序可能会在系统中装载自己的恶意类。这些新加载的类可能被类加载器置于任意保护域中,从而自动将该域的权限授予这些类。
getClassLoader 类加载器的获取(即调用类的类加载器) 这将授予攻击者得到具体类的加载器的权限。这很危险,由于攻击者能够访问类的类加载器,所以攻击者能够加载其他可用于该类加载器的类。通常攻击者不具备这些类的访问权限。
setContextClassLoader 线程使用的上下文类加载器的设置 在需要查找可能不存在于系统类加载器中的资源时,系统代码和扩展部分会使用上下文类加载器。授予 setContextClassLoader 权限将允许代码改变特定线程(包括系统线程)使用的上下文类加载器。
enableContextClassLoaderOverride 线程上下文类加载器方法的子类实现 在需要查找可能不存在于系统类加载器中的资源时,系统代码和扩展部分会使用上下文类加载器。授予enableContextClassLoaderOverride权限将允许线程的子类重写某些方法,这些方法用于得到或设置特定线程的上下文类加载器。
setSecurityManager 设置安全管理器(可能会替换现有的) 安全管理器是允许应用程序实现安全策略的类。授予setSecurityManager权限将通过安装一个不同的、可能限制更少的安全管理器,来允许代码改变所用的安全管理器,因此可跳过原有安全管理器所强制执行的某些检查。
createSecurityManager 创建新的安全管理器 授予代码对受保护的、敏感方法的访问权,可能会泄露有关其他类或执行堆栈的信息。
getenv.{variable name} 读取指定环境变量的值 此权限允许代码读取特定环境变量的值或确定它是否存在。如果该变量含有机密数据,则这项授权是很危险的。
exitVM.{exit status} 暂停带有指定退出状态的Java虚拟机 此权限允许攻击者通过自动强制暂停虚拟机来发起一次拒绝服务攻击。注意:自动为那些从应用程序类路径加载的全部代码授予 “exitVM.*“权限,从而使这些应用程序能够自行中止。此外,”exitVM“权限等于”exitVM.*”。
shutdownHooks 虚拟机关闭钩子 (hook) 的注册与取消 此权限允许攻击者注册一个妨碍虚拟机正常关闭的恶意关闭钩子 (hook)。
setFactory 设置由ServerSocketSocket使用的套接字工厂,或URL使用的流处理程序工厂 此权限允许代码设置套接字、服务器套接字、流处理程序或 RMI套接字工厂的实际实现。攻击者可能设置错误的实现,从而破坏数据流。
setIO System.outSystem.inSystem.err的设置 此权限允许改变标准系统流的值。攻击者可以改变System.in来监视和窃取用户输入,或将System.err设置为”nullOutputStream,从而隐藏发送到System.err的所有错误信息。
modifyThread 修改线程,例如通过调用线程的interruptstopsuspendresumesetDaemonsetPrioritysetNamesetUncaughtExceptionHandler方法 此权限允许攻击者修改系统中任意线程的行为。
stopThread 通过调用线程的stop方法停止线程 如果系统已授予代码访问该线程的权限,则此权限允许代码停止系统中的任何线程。此权限会造成一定的危险,因为该代码可能通过中止现有的线程来破坏系统。
modifyThreadGroup 修改线程组,例如通过调用ThreadGroupdestroygetParentresumesetDaemonsetMaxPrioritystopsuspend方法 此权限允许攻击者创建线程组并设置它们的运行优先级。
getProtectionDomain 获取类的ProtectionDomain 此权限允许代码获得特定代码源的安全策略信息。虽然获得安全策略信息并不足以危及系统安全,但这确实会给攻击者提供了能够更好地定位攻击目标的其他信息,例如本地文件名称等。
getFileSystemAttributes 获取文件系统属性 此权限允许代码获得文件系统信息(如调用者可用的磁盘使用量或磁盘空间)。这存在潜在危险,因为它泄露了关于系统硬件配置的信息以及一些关于调用者写入文件特权的信息。
readFileDescriptor 读取文件描述符 此权限允许代码读取与文件描述符读取相关的特定文件。如果该文件包含机密数据,则此操作非常危险。
writeFileDescriptor 写入文件描述符 此权限允许代码写入与描述符相关的特定文件。此权限很危险,因为它可能允许恶意代码传播病毒,或者至少也会填满整个磁盘。
loadLibrary.{库名} 动态链接指定的库 允许applet具有加载本机代码库的权限是危险的,因为Java安全架构并未设计成可以防止恶意行为,并且也无法在本机代码的级别上防止恶意行为。
accessClassInPackage.{包名} 当类加载器调用SecurityManagercheckPackageAccess方法时,通过类加载器的loadClass方法访问指定的包 此权限允许代码访问它们通常无法访问的那些包中的类。恶意代码可能利用这些类帮助它们实现破坏系统安全的企图。
defineClassInPackage.{包名} 当类加载器调用SecurityManagercheckPackageDefinition方法时,通过类加载器的defineClass 方法定义指定的包中的类。 此权限允许代码在特定包中定义类。这样做很危险,因为具有此权限的恶意代码可能在受信任的包中定义恶意类,比如java.securityjava.lang
accessDeclaredMembers 访问类的已声明成员 此权限允许代码查询类的公共、受保护、默认(包)访问和私有的字段和或方法。尽管代码可以访问私有和受保护字段和方法名称,但它不能访问私有/受保护字段数据并且不能调用任何私有方法。此外,恶意代码可能使用该信息来更好地定位攻击目标。而且,它可以调用类中的任意公共方法和/或访问公共字段。如果代码不能用这些方法和字段将对象强制转换为类/接口,那么它通常无法调用这些方法和/或访问该字段,而这可能很危险。
queuePrintJob 打印作业请求的开始 这可能向打印机输出敏感信息,或者只是浪费纸张。
getStackTrace 获取另一个线程的堆栈追踪信息。 此权限允许获取另一个线程的堆栈追踪信息。此操作可能允许执行恶意代码监视线程并发现应用程序中的弱点。
setDefaultUncaughtExceptionHandler 在线程由于未捕获的异常而突然终止时,设置将要使用的默认处理程序 此权限允许攻击者注册恶意的未捕获异常处理程序,可能会妨碍线程的终止
Preferences 表示得到java.util.prefs.Preferences的访问权所需的权限。java.util.prefs.Preferences实现了用户或系统的根,这反过来又允许获取或更新Preferences 持久内部存储中的操作。 如果运行此代码的用户具有足够的读/写内部存储的OS特权,则此权限就允许用户读/写优先级内部存储。实际的内部存储可能位于传统的文件系统目录中或注册表中,这取决于平台 OS。

可配置项详解

当批量配置的时候,有三种模式:

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

可以通过${}来引用系统属性,如:

"file:$/*"

问题解决

  

取消安全管理器

  

增加相应权限

如果没有某项权限则报错信息会提示是请求什么权限:

1
Exception in thread "main" java.security.AccessControlException: access denied (java.io.FilePermission c:\test.txt write)

c:\test.txt没有写权限。

最简单的事开放所有权限(不推荐):

1
2
3
grant {
permission java.security.AllPermission;
};

快下载安装吧,今天头条送你钱啦!!!!
中国人都在使用的地球上最好玩的游戏
中国人都在使用的地球上最好玩的游戏
中国人都在使用的地球上最快的浏览器
中国人都在使用的地球上最厉害的安全软件
中国人都在使用的地球上最好的看图王
中国人都在使用的地球上最快速的视频软件
中国人都在使用的地球上最全的视频软件
中国人都在使用的地球上最好最全的压缩软件
中国人都在使用的地球上最好的音乐播放器
中国人都在使用的地球上最安全的杀毒软件
中国人都在使用的地球上最全的影视大全