LoginSignup
13
11

More than 5 years have passed since last update.

Javaサンドボックスの中でJavaScriptを動かす

Posted at

Javaのサンドボックスの中でJavaScript(Nashorn)を動かす。やってることはJSR223に対応しているスクリプト言語ならなんでも行けるはずである。

package example.misc;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import java.io.FilePermission;
import java.security.AccessControlContext;
import java.security.AccessControlException;
import java.security.AccessController;
import java.security.AllPermission;
import java.security.CodeSource;
import java.security.PermissionCollection;
import java.security.Permissions;
import java.security.Policy;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.security.ProtectionDomain;
import java.security.cert.Certificate;
import java.util.Arrays;

public class SandboxJSDemo {
    public static void main(final String[] args) {
        // 全許可にしておかないと本体のほうで何もできなくなる
        Policy.setPolicy(new Policy() {
            @Override
            public PermissionCollection getPermissions(
                    final ProtectionDomain domain) {
                final Permissions perms = new Permissions();
                perms.add(new AllPermission());
                return perms;
            }
        });
        // セキュリティマネージャーを有効にする
        System.setSecurityManager(new SecurityManager());

        // Nashornを呼出。JavaScript以外も行ける。
        final ScriptEngineManager engineManager = new ScriptEngineManager();
        final ScriptEngine engine = engineManager.getEngineByName("javascript");
        if (engine == null) {
            throw new RuntimeException("No engine");
        }

        // 空のパーミッションを作成
        final Permissions permissions = new Permissions();
        // /etc/groupの読み込みだけ許可
        permissions.add(new FilePermission("/etc/group", "read"));
        // sandboxの設定
        final ProtectionDomain domain = new ProtectionDomain(
                new CodeSource(null, (Certificate[]) null), permissions);
        final AccessControlContext ctx = new AccessControlContext(
                new ProtectionDomain[]{domain});

        // 色々動かす
        for (final String s : Arrays
                .asList("print('Hello JavaScript')", "load(\"hoge.js\")",
                        "load(\"http://example.org/\")",
                        "java.nio.file.Files.readAllLines(java.nio.file.Paths.get(\"/etc/passwd\"))",
                        "print(java.nio.file.Files.readAllLines(java.nio.file.Paths.get(\"/etc/group\"))[0])")) {
            try {
                AccessController.doPrivileged(
                        (PrivilegedExceptionAction<Object>) () -> engine
                                .eval(s), ctx);
            } catch (AccessControlException | PrivilegedActionException e) {
                System.out.println(e.getMessage());
            }

        }

    }
}

実行すると次のようになる。

Hello JavaScript
access denied ("java.io.FilePermission" "hoge.js" "read")
access denied ("java.net.SocketPermission" "example.org:80" "connect,resolve")
access denied ("java.io.FilePermission" "/etc/passwd" "read")
root:x:0:

/etc/groupだけはアクセスが許可されているので読み取りができる。他のファイルの読み書きやネットワークアクセスは許可がないので拒否されて例外が発生する。

参考

13
11
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
13
11