Javaセキュリティ(その1)

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アタックの歴史
http://java.sun.com/sfaq/chronology.html
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
new
new
new
new
new
new
new
FilePermission("myfile", "read,write");
FilePermission("/home/gong/", "read");
FilePermission("/tmp/mytmp", "read,delete");
FilePermission("/bin/*", "execute");
FilePermission("*", “read”);
FilePermission("/-", "read,execute");
FilePermission("-", "read,execute");
FilePermission("<<ALL FILES>>", "read");
クラスローダ
• クラス・ファイルをロードするオブジェクト
• ClassLoaderクラスのサブクラスの
インスタンス
• クラスの名前空間を作る働きも担っている。
クラス解消アルゴリズム
(class resolution algorithm)
--- SecureClassLoaderの場合
• クラスが既にロードされていないかチェック。
• 現在のクラスローダに委譲関係の親があれば、
親にクラスのロードを委譲。
– SecureClassLoaderは親を指定して作成できる。
– 親が指定されていない場合は、
primordial class loaderに委譲する。
• 親が解消できなければfindClassを呼び出す。
Saraswatのバグ
public class RT {
public static void main(String arg[]) {
RR rr = new RR();
R r = rr.getR();
RTのローダはRをロード。
r.speakUp();
RTのローダはRRのロードを
}
システム・ローダに委譲。
}
システム・ローダはRをロード。
public class RR {
public R getR() { return new R(); }
}
public class R {
public void Icantspeak() { ... }
}
public class R {
public void speakUp() { ... }
}
Tozawaのバグ(その1)
class B extends A { ... }
class C extends A { ... }
public class D {
static boolean t
public D()
{
A a;
if (t)
a = new B();
else
a = new C();
a.speakUp();
}
}
= true;
バイトコード検証系は、
BとCのスーパークラス(の名前)を
Aと計算するが、Aをロードしない。
名前だけでAとAを等しいとみなす。
Tozawaのバグ(その2)
Package java.lang;
public class A {
pulic java.lang.C foo(java.lang.B x)
{
return x;
}
Java2のバイトコード検証系は、
}
システム・クラスを検証しない。
public class D {
public D()
{
java.lang.B b = new java.lang.B();
java.lang.C c = (new java.lang.A()).foo(b);
}
}
バイトコード検証
• バイトコードに対する型推論
• データフロー解析の一種
• JVMのバイトコードには、
バイトコード検証が可能なように、
型の情報が含まれている。
– aload
– iload
– dload
バイトコード検証の問題点
• サブルーチン
– 帰り番地が変数に格納される。
– 必ずしも直接の呼び手に帰らない。
– サブルーチンによって変数の使い方が異なる。(多相性)
• オブジェクトの初期化
– 初期化されていないオブジェクトの参照を
禁止しなければならない。
– ソース・コードでは保証されているが、
バイトコードでは、バイトコード検証系が
保証しなければならない。
バイトコード検証の問題点
• loading constraint schemeとの関連
– 必ずしもloading constraint schemeとの
連携がうまくいっていない。
• システム・クラスや署名付きクラスの検証
– システム・クラスや署名付きクラスは、
その正しさが保証されているので、
バイトコード検証を省略したい。しかし、
安易に省略すると、問題が生じる。
バイトコード検証の定式化
• 型システムによる定式化
–
–
–
–
バイトコードに対する型体系
各命令に対する型規則
バイトコード検証を型推論として定式化する。
型安全性
型推論が成功すれば実行時の型エラーは
起こらない。