Java セキュリティ(その1) 萩谷 昌己 (東京大学) with the help of 戸沢 晶彦 (東京大学)
Java セキュリティの階層 バイトコード検証系 (bytecode verifier) → JDK1.2 ローダ制約 (loader constraint) の導入 クラスローダ (class loader) → JDK1.2 安全なクラスローダ (secure class loader) セキュリティ・マネージャ (security manager) → JDK1.2 アクセス・コントローラ (access controller) RMI セキュリティ拡張 (RMI security extension) JINI セキュリティ
Java アタックの歴史
Java セキュリティ・アーキテ クチャ JDK1.0 砂場モデル (sandbox model) リモート・コード ( 信頼できないコード ) は、 システム・リソースにアクセスできない ( 砂場の中でしか遊べない ) 。 JDK1.1 署名付きアプレット (signed applet) 信頼できる署名の付いたコードは、 ローカル・コードと同様に扱われる。 JDK1.2 保護ドメイン (protection domain) 保護ドメインを単位とした精密なアクセス制 御
保護ドメイン (protection domain) コードベース + 署名者名 – コードベース (codebase) … URL – 署名者名 (signer name) … 複数指定可 (and が取られる )
セキュリティ・ポリシー (security policy) どの保護ドメインに どのような許可 (permission) を与えるか。 ポリシー・ファイル (policy file) による簡潔な 記述 grant [SignedBy "signer_names"] [, CodeBase "URL"] { permission permission_class_name [ "target_name" ] [, "action"] [, SignedBy "signer_names"]; permission … };
アクセス制御 AccessController クラスの checkPermission メソッド その呼び出し方 : FilePermission perm = new FilePermission("path/file", "read"); AccessController.checkPermission(perm); 現在の実行コンテキストのもとで、 アクセスの許可を調べる。
アクセス制御 アルゴリズム : i = m; while (i > 0) { if ( caller i 's domain does not have the permission ) throw AccessControlException; else if ( caller i is marked as privileged ) return; i = i - 1; }; inheritedContext.checkPermission(permission); inheritedContext … 親スレッドのコンテキスト
特権 (previlege) 実行コンテキストに特権を与える。 class A implements PrivilegedAction { Object run() {... } } A a = new A(); Object o = AccessController.doPrivileged(a); 実行コンテキストに privileged のマークが付い て、 run メソッドが実行される。 run メソッドの実行中は、 doPrivileged の呼び手のところで、 アクセスのチェックが終了する。
アクセス制御コンテキスト コンテキストの取得 : AccessControlContext acc = AccessController.getContext(); コンテキストを指定した制御 : acc.checkPermission(permission); コンテキストを指定した特権の付与 : Object o = AccessController.doPrivileged(a, acc);
アルゴリズム (コンテキストの指定がある場 合) : i = m; while (i > 0) { if ( caller i 's domain does not have the permission ) throw AccessControlException; else if ( caller i is marked as privileged ) if ( a context was specified in the call to doPrivileged) context.checkPermission(permission); return; i = i - 1; }; inheritedContext.checkPermission(permission); アクセス制御
Permission クラス 抽象クラス abstract boolean implies(Permission permission) – a.implies(b) は、許可 a が許可 b を 包含することを意味する。 サブクラス : –AllPermission, BasicPermission, –FilePermission, SocketPermission, –UnresolvedPermission
FilePermission クラス new FilePermission("myfile", "read,write"); new FilePermission("/home/gong/", "read"); new FilePermission("/tmp/mytmp", "read,delete"); new FilePermission("/bin/*", "execute"); new FilePermission("*", “read”); new FilePermission("/-", "read,execute"); new FilePermission("-", "read,execute"); new FilePermission(" >", "read");
クラスローダ クラス・ファイルをロードするオブ ジェクト ClassLoader クラスのサブクラスの インスタンス クラスの名前空間を作る働きも担って いる。
クラス解消アルゴリズム (class resolution algorithm) --- SecureClassLoader の場合 クラスが既にロードされていないかチェック。 現在のクラスローダに委譲関係の親があれば、 親にクラスのロードを委譲。 –SecureClassLoader は親を指定して作成でき る。 – 親が指定されていない場合は、 primordial class loader に委譲する。 親が解消できなければ findClass を呼び出 す。
public class RT { public static void main(String arg[]) { RR rr = new RR(); R r = rr.getR(); r.speakUp(); } public class RR { public R getR() { return new R(); } } public class R { public void Icantspeak() {... } } public class R { public void speakUp() {... } } Saraswat のバグ RT のローダは R をロード。 RT のローダは RR のロードを システム・ローダに委譲。 システム・ローダは R をロード。
class B extends A {... } class C extends A {... } public class D { static boolean t = true; public D() { A a; if (t) a = new B(); else a = new C(); a.speakUp(); } Tozawa のバグ(その1) バイトコード検証系は、 B と C のスーパークラス(の名前)を A と計算するが、 A をロードしない。 名前だけで A と A を等しいとみなす。
Package java.lang; public class A { pulic java.lang.C foo(java.lang.B x) { return x; } public class D { public D() { java.lang.B b = new java.lang.B(); java.lang.C c = (new java.lang.A()).foo(b); } Tozawa のバグ(その2) Java2 のバイトコード検証系は、 システム・クラスを検証しない。
バイトコード検証 バイトコードに対する型推論 データフロー解析の一種 JVM のバイトコードには、 バイトコード検証が可能なように、 型の情報が含まれている。 –aload –iload –dload
バイトコード検証の問題点 サブルーチン – 帰り番地が変数に格納される。 – 必ずしも直接の呼び手に帰らない。 – サブルーチンによって変数の使い方が異なる。(多 相性) オブジェクトの初期化 – 初期化されていないオブジェクトの参照を 禁止しなければならない。 – ソース・コードでは保証されているが、 バイトコードでは、バイトコード検証系が 保証しなければならない。
loading constraint scheme との関連 – 必ずしも loading constraint scheme との 連携がうまくいっていない。 システム・クラスや署名付きクラスの 検証 – システム・クラスや署名付きクラスは、 その正しさが保証されているので、 バイトコード検証を省略したい。しかし、 安易に省略すると、問題が生じる。 バイトコード検証の問題点
バイトコード検証の定式化 型システムによる定式化 – バイトコードに対する型体系 – 各命令に対する型規則 – バイトコード検証を型推論として定式化す る。 – 型安全性 型推論が成功すれば実行時の型エラーは 起こらない。