LoginSignup
8
5

More than 1 year has passed since last update.

Java Security Managerを有効にしてSpring Bootを起動する

Last updated at Posted at 2021-05-14

Spring BootをJavaのSecurity Managerと一緒に起動することで、お手軽にサンドボックス化できます。例えば外部から送られてくるスクリプトをアプリケーション上で実行しなきゃいけないけど、セキュリティが不安な時とか。

2021/05/17 2:07 JST: 実際に試してみたら工夫が必要だったので説明を加えました。 見切り発車で書いてました。ごめんなさい。

Java Security Manager

JavaのSecurity Managerという機能を有効にすると、プログラムが実行してもよい操作を制限することができます。例えばファイルや環境変数の読み書き、ネットワークへの接続など、想定外の挙動をした場合にそれを検知して、失敗させることができます。
許可する権限はポリシーファイルというものに書き連ねます。

example.policy
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側のコンパイルが通ります。

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

ポリシーはこんな感じになります。

example.policy
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

Security Managerのオプションも付ければ完成!

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のバグらしく、GitHubに報告されてから2年近くたった今も直っていません(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

8
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
5