Javaによるお気楽なサンドボックス環境の作り方(セキュリティーマネージャ)

Javaで #appengine のようなサンドボックス環境を作る場合、SecurityManagerを使用するのがよさそうです。

http://itref.fc2web.com/java/security.html

具体的には、ポリシーファイルというものを書くという形になります。

(以下は転載)

grant {
permission java.util.PropertyPermission "test_prop", "write,read";
permission java.io.FilePermission "c:/temp/test.txt", "read,write";
//permission java.io.FilePermission "<>", "read,write";
};

しかし、今時のWebアプリなら、実行環境ごとに設定をお願いするのではなく、warをデプロイするだけで、必要な設定はなされていてくれる方がありがたいです。また、policyファイルのような外部ファイルを使うのではなく、純粋にJavaだけで制御すればデバッガもろもろが使えて便利ですよね?

policyファイルを使用しない方法は、java.lang.SecurityManager を独自にオーバーライドすることで実現できます。

http://java.sun.com/javase/ja/6/docs/ja/api/java/lang/SecurityManager.html

そして、こんな感じにします。

public class MySecurityManager extends SecurityManager {
@Override
public void checkExit(int status) {
throw new SecurityException("system exit is not supported.");
}
}
System.setSecurityManager(new MySecurityManager());

しかし、これだと、環境にセキュリティーマネージャが設定されている場合は、その実装が殺されてしまいます。ということは、セキュリティーが考慮された環境でこれを行った場合、ヘタをすると、セキュリティーを低下させてしまいかねません。

※もちろん、よく設定された環境では、セキュリティマネージャの設定自体が許されない可能性もあります。

そう思うと気が重いことです。なかなか手をつけられません。

そこで、既存のセキュリティマネージャを生かしつつ、独自のセキュリティーチェックをJavaだけで実装しようとする場合は、以下のようにすれば良さそうです。

public class NullSecurityManager extends SecurityManager {
@Override
public void checkPermission(Permission perm, Object context) {
// なにもしない
}
@Override
public void checkPermission(Permission perm) {
// なにもしない
}
}
public class MySecurityManager extends NullSecurityManager {
private SecurityManager innerSecurityManager;
public MySecurityManager(SecurityManager innerSecurityManager) {
if (innerSecurityManager == null) {
innerSecurityManager = new NullSecurityManager();
}
this.innerSecurityManager = innerSecurityManager;
}
@Override
public void checkPermission(Permission perm) {
innerSecurityManager.checkPermission(perm);
}
@Override
public void checkPermission(Permission perm, Object context) {
innerSecurityManager.checkPermission(perm, context);
}
@Override
public void checkCreateClassLoader() {
innerSecurityManager.checkCreateClassLoader();
}
public void checkExit(int status) {
innerSecurityManager.checkExit(status);
throw new SecurityException("system exit is not supported.");
}
// 以下あらゆるメcheck系メソッドを委譲
}

あとは、Servletの起動時に

try {
SecurityManager securityManager = System.getSecurityManager();
if (!(securityManager instanceof MySecurityManager)) {
System.setSecurityManager(new MySecurityManager(securityManager));
}
} catch (SecurityException e) {
System.out.println("cannot set my SecurityManager");
}

こんな感じで動きました。

コメントを残す