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
37
> 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
7
> [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
48
> 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
10
> #清空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
6
> [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
2
> 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
33
> ***************************************
> 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!