参考文档1:https://www.zybuluo.com/changedi/note/237999
参考文档2:https://benjaminwhx.com/2018/06/19/AccessController-doPrivileged/
起因是在学习JDBC驱动加载机制(SPI-接口与实现分离,实现解耦,参考文档:https://juejin.im/post/5b9b1c115188255c5e66d18c)的时候碰到如下代码:
1 | try { |
大意是通过特权的方式突破当前域权限的限制,临时扩大访问权限,获取系统资源。
这是为了在开启java的沙箱机制的程序中获得执行代码的权限。java沙箱机制参考以上文档介绍。
运行java程序时默认是不开启沙箱机制的,要开启沙箱机制加入启动参数:
1 | -Djava.security.manager |
开启沙箱机制后,java的安全管理器SecurityManager即起作用了,安全管理器会去读策略文件来判断java类的执行权限,默认的策略文件$JREHOME/lib/security/java.policy,可以命令行参数指定策略文件:
1 | -Djava.security.policy=xx.policy |
下面通过一个创建文件的例子来说明开启沙箱后的权限验证和AccessController.doPrivileged的特权作用
- vim FileUtil.java
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 package com.leo.security;
import java.io.File;
import java.io.IOException;
import java.security.AccessControlException;
import java.security.AccessController;
import java.security.PrivilegedAction;
/**
*
*/
public class FileUtil {
private final static String FOLDER_PATH = "/Users/qiaojian/Downloads/";
public static void makeFile(String fileName) {
try {
File fs = new File(FOLDER_PATH + fileName);
fs.createNewFile();
} catch (AccessControlException | IOException e) {
e.printStackTrace();
}
}
public static void doPrivilegedAction(final String fileName) {
// 用特权访问方式创建文件
AccessController.doPrivileged( new PrivilegedAction<String> () {
public String run() {
makeFile(fileName);
return null;
}
});
}
}
- 将此java文件打包成一个项目jar包
1
2
3
4
5
6 [qiaojian@Mac security ]% mkdir target
[qiaojian@Mac security ]% javac FileUtil.java -d target
[qiaojian@Mac security ]% jar cvf file-util.jar -C target/ .
将此jar包放到lib目录下供其他项目使用
[qiaojian@Mac security ]% mkdir lib
[qiaojian@Mac security ]% mv file-util.jar lib/
- vim PrivilegeTest.java
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 package com.leo.security;
import java.io.File;
import java.io.IOException;
import java.security.AccessControlException;
/**
*
*/
public class PrivilegeTest {
public static void main(String[] args) {
System.out.println("***************************************");
System.out.println("I will show AccessControl functionality...");
System.out.println("Preparation step : turn on system permission check...");
// 打开系统安全权限检查开关,添加vm options: -Djava.security.manager
// 使用特定policy,添加vm options: -Djava.security.policy=privilegetest.policy
System.out.println();
System.out.println("#########################################");
System.out.println("Create a new file named privilege1.txt via privileged action ...");
FileUtil.doPrivilegedAction("privilege1.txt");
System.out.println("#########################################");
System.out.println();
System.out.println("/////////////////////////////////////////");
System.out.println("Create a new file named privilege2.txt via File ...");
try {
File fs = new File (
"/Users/qiaojian/Downloads/privilege2.txt");
fs.createNewFile();
} catch (IOException | AccessControlException e) {
e.printStackTrace();
}
System.out.println("/////////////////////////////////////////");
System.out.println();
System.out.println("-----------------------------------------");
System.out.println("create a new file named privilege3.txt via FileUtil ...");
FileUtil.makeFile("privilege3.txt");
System.out.println("-----------------------------------------");
System.out.println();
System.out.println("***************************************");
}
}
- 将此java文件打包成另一个项目jar包
1
2
3
4
5
6
7
8
9 清空target目录,重新编译PrivilegeTest.java
[qiaojian@Mac security ]% cd target;
[qiaojian@Mac security ]% rm -rf *;
[qiaojian@Mac security ]% cd ..
[qiaojian@Mac security ]% javac -cp lib/file-util.jar PrivilegeTest.java -d target
打包并指定Main-Class所在类
[qiaojian@Mac security ]% jar cvfe privilege-test.jar com.leo.security.PrivilegeTest -C target/ .
修改META-INF/MANIFEST.MF,添加Class-Path: lib/file-util.jar
[qiaojian@Mac security ]% vim privilege-test.jar
- 编辑自定义策略文件,授权只有项目file-util.jar可以写文件到指定目录
1
2
3
4
5 [qiaojian@Mac security ]% vim privilegetest.policy
[qiaojian@Mac security ]% cat privilegetest.policy [0]
grant codeBase "file:/Users/qiaojian/Downloads/Test/testmybatis/src/main/java/com/leo/security/lib/-" {
permission java.io.FilePermission "/Users/qiaojian/Downloads/*", "write";
};
- 运行程序,指定开启沙箱机制,指定策略文件
1 java -Djava.security.manager -Djava.security.policy=privilegetest.policy -jar privilege-test.jar从输出可见,项目privilege-test.jar只有通过AccessController.doPrivileged 方式才可以成功创建文件privilege1.txt
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 ***************************************
I will show AccessControl functionality...
Preparation step : turn on system permission check...
#########################################
Create a new file named privilege1.txt via privileged action ...
#########################################
/////////////////////////////////////////
Create a new file named privilege2.txt via File ...
java.security.AccessControlException: access denied ("java.io.FilePermission" "/Users/qiaojian/Downloads/privilege2.txt" "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.SecurityManager.checkWrite(SecurityManager.java:979)
at java.io.File.createNewFile(File.java:1008)
at com.leo.security.PrivilegeTest.main(PrivilegeTest.java:31)
/////////////////////////////////////////
-----------------------------------------
create a new file named privilege3.txt via FileUtil ...
java.security.AccessControlException: access denied ("java.io.FilePermission" "/Users/qiaojian/Downloads/privilege3.txt" "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.SecurityManager.checkWrite(SecurityManager.java:979)
at java.io.File.createNewFile(File.java:1008)
at com.leo.security.FileUtil.makeFile(FileUtil.java:19)
at com.leo.security.PrivilegeTest.main(PrivilegeTest.java:40)
-----------------------------------------
***************************************