启用Java安全管理器,并启动Spring Boot

通过将Spring Boot与Java的Security Manager一起启动,可以轻松地进行沙盒化。例如,当需要在应用程序上执行来自外部的脚本但安全性不可靠时。

2021/05/17 2:07 JST:由于实际尝试需要一些技巧,我补充了一些解释。之前是匆忙写的,对不起。

Java 安全管理器

如果启用Java的安全管理器功能,可以限制程序可以执行的操作。例如读写文件、读取环境变量、连接到网络等。当出现意外行为时,可以通过检测并阻止其执行来避免失败。
允许的权限需要写入到一个称为策略文件的文件中。

grant {
    // 全て許可する
    permission java.security.AllPermission;
};

而当执行Java时,还需要加上-Djava.security.manager和-Djava.security.policy选项。如果只有-Djava.security.manager,将使用默认的策略文件。

java -Djava.security.manager -Djava.security.policy=example.policy

使用Spring Boot启用Security Manager

如果想要与Spring Boot一起使用Security Manager,就需要做一些小的调整。

准备好

政策不能针对单独的包或类进行设置,只能针对jar文件或jar文件所在的目录进行设置。因此,Spring Boot的jar文件需要允许所有操作(否则无法启动Tomcat等),需要将希望受限制的程序打包到外部的jar文件中。
一个类似的形象。

./
├─ libs/              <== 制限したいプログラムをいれる場所
│  └─ myutils.jar
├─ example.policy
└─ my_application.jar <== Spring Bootの実行可能jar

如果使用Gradle,可以通过使用compileOnly files来指定外部jar文件,以使Spring Boot编译通过。

dependencies {
    ...
    compileOnly files('libs/myutils.jar')
}

政策会是这样的感觉。

grant codeBase "file:my_application.jar" {
    // Spring Bootアプリケーションには全て許可する
    permission java.security.AllPermission;
};

grant codeBase "file:libs/*" {
    // 例: libs内のjarには、my_test.txtの読み書きだけ許可する
    permission java.io.FilePermission "C:/my_test.txt", "read,write";
};

在执行Spring Boot时,您可以使用PropertiesLauncher来指定额外的类路径。
像下面的命令一样,在执行Spring Boot时使用-Dloader.path来设置额外的类路径libs/并启动。

java -cp my_application.jar -Dloader.path=libs/ org.springframework.boot.loader.PropertiesLauncher

如果加上安全经理的选项,就完成了!

java -cp my_application.jar -Djava.security.manager -Djava.security.policy=example.policy -Dloader.path=libs/ org.springframework.boot.loader.PropertiesLauncher

执行

这看起来可以,但在JDK 15上进行时会出现一些错误。

$ java -version
java version "15.0.1" 2020-10-20
Java(TM) SE Runtime Environment (build 15.0.1+9-18)
Java HotSpot(TM) 64-Bit Server VM (build 15.0.1+9-18, mixed mode, sharing)

$ java -cp my_application.jar -Djava.security.manager -Djava.security.policy=example.policy -Dloader.path=libs/ org.springframework.boot.loader.PropertiesLauncher
Exception in thread "main" java.lang.ClassNotFoundException: com.github.otoiku.Application
        at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:435)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:589)
        at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:151)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
        at java.base/java.lang.Class.forName0(Native Method)
        at java.base/java.lang.Class.forName(Class.java:468)
        at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:46)
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:107)
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:58)
        at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:88)

如果使用的是JDK 11及以上版本的话

总的来说,添加-Dsun.misc.URLClassPath.disableJarChecking选项可以解决这个问题。

$ java -cp my_application.jar -Djava.security.manager -Dsun.misc.URLClassPath.disableJarChecking -Djava.security.policy=example.policy -Dloader.path=libs/ org.springframework.boot.loader.PropertiesLauncher

从JDK 11时代开始就存在的Spring Boot的一个bug似乎至今没有修复(截至2021年5月)。可以在以下链接中找到有关该问题的报告:
https://stackoverflow.com/questions/54063602/springboot-on-open-jdk-11-classnotfound-errors-when-securitymanager-is-activ
https://github.com/spring-projects/spring-boot/issues/17796
https://github.com/spring-projects/spring-boot/issues/25538

广告
将在 10 秒后关闭
bannerAds