java沙箱

参考文档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
2
3
4
5
6
7
8
9
try {
drivers = AccessController.doPrivileged(new PrivilegedAction<String>() {
public String run() {
return System.getProperty("jdbc.drivers");
}
});
} catch (Exception ex) {
drivers = null;
}

大意是通过特权的方式突破当前域权限的限制,临时扩大访问权限,获取系统资源。

这是为了在开启java的沙箱机制的程序中获得执行代码的权限。java沙箱机制参考以上文档介绍。

运行java程序时默认是不开启沙箱机制的,要开启沙箱机制加入启动参数:

1
-Djava.security.manager

开启沙箱机制后,java的安全管理器SecurityManager即起作用了,安全管理器会去读策略文件来判断java类的执行权限,默认的策略文件$JREHOME/lib/security/java.policy,可以命令行参数指定策略文件:

1
-Djava.security.policy=xx.policy

下面通过一个创建文件的例子来说明开启沙箱后的权限验证和AccessController.doPrivileged的特权作用

  1. 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> () {
@Override
public String run() {
makeFile(fileName);
return null;
}
});
}

}
  1. 将此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/
  1. 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("***************************************");
}
}
  1. 将此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
  1. 编辑自定义策略文件,授权只有项目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. 运行程序,指定开启沙箱机制,指定策略文件
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)
-----------------------------------------

***************************************
-------------本文结束感谢您的阅读-------------
Good for you!