Java SecurityManager初识
source link: https://blog.spoock.com/2019/12/21/Getting-Started-with-Java-SecurityManager-from-Zero/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Java SecurityManager初识
最近整理文档的时候,发现在角落里躺着几篇有关Java SecurityManager的文章,最近也没有精力研究Java安全了,就将文章分享出来。
根据Oracle官方对The Security Manager
的说明:
A security manager is an object that defines a security policy for an application. This policy specifies actions that are unsafe or sensitive. Any actions not allowed by the security policy cause a SecurityException to be thrown. An application can also query its security manager to discover which actions are allowed. Typically, a web applet runs with a security manager provided by the browser or Java Web Start plugin. Other kinds of applications normally run without a security manager, unless the application itself defines one. If no security manager is present, the application has no security policy and acts without restrictions.
翻译为中文的意思是:Security Manager
是用于对一个应用程序定义一个安全策略的对象。这个策略能够定义一些不安全或者是敏感操作。不被安全策略允许的操作将会抛出SecurityException
。同样地,利用Security Manager
还可以定义一些允许执行的操作。默认情况下,oracle
已经对Security Manager
能够控制的操作进行了说明Permissions in the Java Development Kit (JDK),包括Socket
、文件、序列化、反射等权限。
Security Manager
主要是在运行时检查。默认情况下,直接运行的Java程序都没有开启SecurityManager。如果程序开启了SecurityManager
,那么程序所进行的任何操作最终都会进入到Security Manager
进行检查判断。Java程序有两种方式开启Security Manager
以及定义操作。这两种方式都会在本文中进行说明。
- 自定义
SecurityManager
策略文件 - 继承
SecurityManager
,通过代码的方式,对每个操作进行控制。
自定义SecurityManager
策略文件
虽然Java程序默认没有开启Security Manager
,但是我们可以通过在JVM启动参数中加上-Djava.security.manager
开启。具体用法是java -Djava.security.manager classfile
。开启之后,JVM首先会去${java.home}/jre/lib/security
寻找java.security
文件。在java.security
定义了很多与安全相关的配置。例如
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
# List of comma-separated packages that start with or equal this string
# will cause a security exception to be thrown when
# passed to checkPackageAccess unless the
# corresponding RuntimePermission ("accessClassInPackage."+package) has
# been granted.
package.access=sun.,\
com.sun.xml.internal.,\
com.sun.imageio.,\
com.sun.istack.internal.,\
com.sun.jmx.,\
com.sun.media.sound.,\
com.sun.naming.internal.,\
com.sun.proxy.,\
com.sun.corba.se.,\
com.sun.org.apache.bcel.internal.,\
....
# List of comma-separated packages that start with or equal this string
# will cause a security exception to be thrown when
# passed to checkPackageDefinition unless the
# corresponding RuntimePermission ("defineClassInPackage."+package) has
# been granted.
#
# by default, none of the class loaders supplied with the JDK call
# checkPackageDefinition.
#
package.definition=sun.,\
com.sun.xml.internal.,\
com.sun.imageio.,\
com.sun.istack.internal.,\
com.sun.jmx.,\
com.sun.media.sound.,\
com.sun.naming.internal.,\
com.sun.proxy.,\
如果直接访问package.access
和package.definition
中的类会抛出security exception
,除非这些定义的类是被允许的。
还有比如:
1
2
3
4
# Determines whether this properties file can be appended to
# or overridden on the command line via -Djava.security.properties
#
security.overridePropertiesFile=true
设置了security.overridePropertiesFile=true
表示可以覆盖或者是扩展默认的策略的配置文件。(这一点在后面会进行说明)
还有类似于以-Djava.security.policy=somefile
的方式载入自定义的策略文件:
1
2
3
4
# whether or not we allow an extra policy to be passed on the command line
# with -Djava.security.policy=somefile. Comment out this line to disable
# this feature.
policy.allowSystemProperty=true
其中还包括了策略文件的定义:
1
2
3
4
# The default is to have a single system-wide policy file,
# and a policy file in the user's home directory.
policy.url.1=file:${java.home}/lib/security/java.policy
policy.url.2=file:${user.home}/.java.policy
默认的策略文件的定义是在${java.home}/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
// Standard extensions get all permissions by default
grant codeBase "file:${{java.ext.dirs}}/*" {
permission java.security.AllPermission;
};
// default permissions granted to all domains
grant {
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";
};
分析java.policy
文件
"file:$/*"
使用了permission java.security.AllPermission
,表示开启了所有的权限。permission java.lang.RuntimePermission "stopThread";
表示运行调用进程的暂停方法。- 系统属性的读取,如
permission java.util.PropertyPermission "java.version", "read";
表示允许读取java.version
。
我们以permission java.util.PropertyPermission "java.version", "read";
为例进行说明。编写测试文件
Test.java
1
2
3
4
5
6
7
public class Test {
public static void main(String[] args) {
System.out.println(System.getProperty("java.version"));
System.setProperty("java.version","123");
System.out.println(System.getProperty("java.version"));
}
}
在不开启Security Manager
的情况下运行java Test
得到的结果是:
1
2
3
$ java Test
1.8.0_161
123
可以看到通过System.setProperty("java.version","123");
,我们改变了java.version
的值。
开启Security Manager
的情况下运行java Test
得到的结果是:
1
2
3
4
5
6
7
8
$ java -Djava.security.manager Test
1.8.0_161
Exception in thread "main" java.security.AccessControlException: access denied ("java.util.PropertyPermission" "java.version" "write")
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:472)
at java.security.AccessController.checkPermission(AccessController.java:884)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
at java.lang.System.setProperty(System.java:792)
at Test.main(Test.java:4)
由于在默认的java.policy
中仅仅只是设置允许读取java.version
,所以尝试进行设置java.version
就会抛出AccessControlException
异常。
我们可以自定义我们的策略文件。例如我自定义的策略文件如下:my.policy
1
2
3
grant {
permission java.util.PropertyPermission "java.version", "read";
};
表示只会允许读取java.version
信息。
Test.java
1
2
3
4
5
6
7
8
9
import java.io.IOException;
public class Test {
public static void main(String[] args) throws IOException {
System.out.println(System.getProperty("java.version"));
System.setProperty("java.version","123");
System.out.println(System.getProperty("java.version"));
}
}
我们的策略文件的写法是:my.policy
1
2
3
grant {
permission java.util.PropertyPermission "java.version", "write";
};
使用添加模式,命令是java -Djava.security.manager -Djava.security.policy=D:/my.policy
(注意其中的-Djava.security.policy=D:/my.policy
只有一个等号)。得到的结果如下:
1
2
3
$ java -Djava.security.manager -Djava.security.policy=D:/my.policy Test
1.8.0_161
123
如果我们变为覆盖模式,命令是java -Djava.security.manager -Djava.security.policy==D:/my.policy
(注意其中的-Djava.security.policy==D:/my.policy
只有两个等号)。得到的结果如下:
1
2
3
4
5
6
7
8
$ java -Djava.security.manager -Djava.security.policy==D:/my.policy Test
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:884)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
at java.lang.SecurityManager.checkPropertyAccess(SecurityManager.java:1294)
at java.lang.System.getProperty(System.java:717)
at Test.main(Test.java:8)
可以看到直接报错,因为此时只为java.version
设置了write
权限没有读权限,所以System.getProperty("java.version")
就会报错。
以上就是利用策略文件实现对于权限的访问控制。
The Security Manager
Java安全管理器-SecurityManager
Permissions in the Java Development Kit (JDK)
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK