Since: May/23rd/2004
セキュリティマネージャやアクセスコントローラーはインタフェースや抽象クラスで提供されているので、それらを実装したり継承することで、独自の管 理クラスを開発することも可能ですが、一般には、セキュリティーポリシをポリシファイルと呼ばれるテキストファイルに記述することで宣言します。ここで、 ポリシファイルの中身について、少し詳しく説明します。
ポリシファイルは単純なテキストなので、テキストエディターで編集しますが、SDKではグラフィカルな編集ツールpolicytoolも提供してい ます。起動するには、コマンドラインでコマンド"policytool"を発行します。ポリシファイルの構文の詳細を隠蔽してくれます。詳細は、Sunのドキュメントを参照してください。
![]() |
| 図1. policytool |
|---|
デフォルトのシステムポリシファイルは、"${java.home}/lib/security/java.policy"にあります。例えば、Java 2 SDK 1.4.2_04のデフォルトでは "C:\j2sdk1.4.2_04\jre\lib\security" になります。ユーザポリシファイルは、デフォルトでは "${user.home}/.java.policy" から探索されます。
任意の場所に置く場合は、セキュリティプロパティで指定します。システムプロパティ "java.security.policy" で指定する方法と、セキュリティプロパティファイル "${java.home}/security/java.security" に記述する方法があります。このファイルには、リスト1の行が含まれています。
リスト1. java.security ファイルの抜粋
# The default is to have a single system-wide policy file,
# and a policy file in the user's home directory.
policy.url.1=file:${java.home}/lib/security/java.policy
policy.url.2=file:${user.home}/.java.policy
読み込むファイルを policy.url.[n] に追加します。一方、実行時引数で指定する場合のjavaコマンドは次のようになります。
C:\java>java -Djava.security.policy=MyDemo.policy MyDemo
セキュリティマネージャのインストールをコードに含んでいない場合は、これもオプションで指定する必要があります:
C:\java>java -Djava.security.manager -Djava.security.policy=MyDemo.policy MyDemo
リスト2に挙げるのが、システムデフォルトのポリシファイルです。最初のgrantエントリーでは、"jre/lib/ext/"
からロードされるクラスファイルとJAR(拡張パッケージ)に対してすべてのアクセス権が与えられています。次のgrantエントリーでは、すべてのクラ
スに対して、ローカルホストの1024番以降のポートをlisten可能であり、リストされているすべてのシステムプロパティを読み取り可能に設定されて
います。
リスト2. デフォルトポリシファイル
// Standard extensions get all permissions by default
grant codeBase "file:${java.home}/lib/ext/*" {
permission java.security.AllPermission;
};
// default permissions granted to all domains
grant {
// Allows any thread to stop itself using the java.lang.Thread.stop()
// method that takes no argument.
// Note that this permission is granted by default only to remain
// backwards compatible.
// It is strongly recommended that you either remove this permission
// from this policy file or further restrict it to code sources
// that you specify, because Thread.stop() is potentially unsafe.
// See "http://java.sun.com/notes" for more information.
permission java.lang.RuntimePermission "stopThread";
// allows anyone to listen on un-privileged ports
permission java.net.SocketPermission "localhost:1024-", "listen";
// "standard" properies that can be read by anyone
permission java.util.PropertyPermission "java.version", "read";
permission java.util.PropertyPermission "java.vendor", "read";
permission java.util.PropertyPermission "java.vendor.url", "read";
permission java.util.PropertyPermission "java.class.version", "read";
permission java.util.PropertyPermission "os.name", "read";
...
// 省略
...
};
各ポリシファイルには、一つ以下のkeystoreエントリーと複数のgrantエントリーが含まれます。デフォルトファイルにはgrantエントリーしかありません。
ポリシファイルには、最大一つの keystore エントリーと、複数個の grant エントリーを書くことできます。grant エントリーは、コードやプリンシパルに対して、許可するアクセス権を付与するためのものであり、keystore エントリーは、鍵と証明書を保持するキーストアを指定するものです。
grantエントリーは、クラスがロードされるURLに対して、そのクラスに許されるアクセス権の種類とその内容を明示するものです。SDK 1.4での書式はリスト3のようになります。
リスト3. grantエントリーのシンタックス
grant [SignedBy "signer_names"] [, CodeBase "URL"]
[, Principal [principal_class_name] "principal_name"]
[, Principal [principal_class_name] "principal_name"] ... {
permission permission_class_name [ "target_name" ]
[, "action"] [, SignedBy "signer_names"];
permission ...
};
CodeBaseフィールドは、クラスがロードされたURLを示します。省略されたら、すべてのクラスに対して適用されます。アクセス権の行には、 アクセス権に対応するクラスの完全限定名とそのターゲット及びアクションが示されます。例えば、システムプロパティ"java.version"に対する "read"権限を与える場合は次のように書きます:
permission java.util.PropertyPermission "java.version", "read";
同様に、ローカルファイルシステムのディレクトリ"/tmp"内のすべてのファイル及び再帰的にアクセスされるすべてのサブディレクトリ内のファイルに対する読み取りと実行の権限を与えるには、次のように記述します。
java.io.FilePermission "/tmp/-", "read, execute";"
アクセス権についての詳細は、Sunのドキュメントを参照してください。
SignedByフィールドは、後で説明する、署名されたクラスの場合に、署名を検証する証明書を指定するためのフィールドです。これを指定する場 合は、同じポリシファイルのkeystoreエントリーで得られるキーストアの公開鍵と証明書によって検証されます。デフォルトのファイルでは省略されて おり、すべての署名が許されます。
Principalフィールドは、アクセス権を付与するユーザと関連付けられます。SDK 1.4でコア・パッケージに追加されたJAAS (Authentication and Authorization Service)で使われ、ここで指定したプリンシパル名は、JAASのログインモジュールで認証されたサブジェクトと関連付けられ指定した権限を付与し ます。デフォルトで利用できるのは、パッケージ"com.sun.security.auth"に含まれる次の5つの認証方法です。
例えば、Windows環境でログイン名が"msugai"であれば、grantエントリーは次のようになります:
grant com.sun.security.auth.NTLoginModule "msugai" {
...
// 省略
...
};
デフォルトでは省略されており、すべてのプリンシパルが許されます。本稿ではJAASの詳細については説明しません。詳細は、Sunのドキュメントを参照してください。
ポリシファイルには、grantエントリーのほかに、keystoreエントリーも記述できます。キーストアとは、鍵とその証明書を保持するもので す。keystoreエントリーは、そのファイルのgrantエントリのSignedByフィールドで指定した公開鍵を照合するために使用されます。構文 は次のようになります:
keystore "some_keystore_url", "keystore_type";
URLにはキーストアが得られるパスを記述し、typeにはキーストアのフォーマットを指定します。
ポリシファイルに関する詳細は、Sunのドキュメントを参照してください。
ポリシファイルを用意して、そのポリシにもとる操作を実行してみます。リスト4のファイル MyDemo.policy を用意して、リスト5を実行してみると、リスト6のようにセキュリティ例外が返され、実行は拒否されます。
リスト4. MyDemo.policy
grant codeBase "file:/C:/java/*" {
permission java.io.FilePermission "out.txt", "read";
};
リスト5. FileIO.java
import java.security.*;
import java.io.*;
class FileIO {
public static void main(String args[]) {
try {
BufferedReader in = new BufferedReader(
new InputStreamReader(System.in));
BufferedWriter out = new BufferedWriter(
new FileWriter("out.txt", true));
String str="";
while(!str.equals("x")){
System.out.print("行> ");
str=in.readLine();
out.write(str);
out.newLine();
out.flush();
out.close();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
}
}
}
リスト6. FileIO の実行結果
>java -Djava.security.manager -Djava.security.policy=MyDemo.policy FileIO
java.security.AccessControlException: access denied (java.io.FilePermission out.
txt write)
at java.security.AccessControlContext.checkPermission(Unknown Source)
at java.security.AccessController.checkPermission(Unknown Source)
at java.lang.SecurityManager.checkPermission(Unknown Source)
at java.lang.SecurityManager.checkWrite(Unknown Source)
at java.io.FileOutputStream.(Unknown Source)
at java.io.FileOutputStream.(Unknown Source)
at java.io.FileWriter.(Unknown Source)
at FileIO.main(FileIO.java:14)
次に、リスト1に挙げた、アクセス権チェックのメソッド AccessController.checkPermission() を実行してみます。リスト5 の処理内容を、リスト7 のように変更することで、リスト8 のように例外が得られます。失敗する前に例外を捕捉できるので、ユーザから実装を隠蔽できるメリットがあります。
リスト7. アクセス権チェック
// 問い合わせるアクセス権を意味するオブジェクトを生成
FilePermission perm = new FilePermission("./out.txt", "write");
// アクセスコントローラにてチェック
AccessController.checkPermission(perm);
リスト8. アクセス権チェックの実行結果
>java -Djava.security.manager -Djava.security.policy=MyDemo.policy FileIO
行> hellojava.lang.NullPointerException
at java.io.Writer.write(Unknown Source)
at FileIO.main(FileIO.java:21)
次に挙げるのは、ガードオブジェクトの実装例です。 java.security.GuardedObject 型オブジェクトは、オブジェクトのアクセス権チェックを実行時まで遅延するための仕組みです。コンストラクタの引数には、保護対象のオブジェクトと、java.security.Guard 型オブジェクトを指定します。Guardはインタフェースであり、実際には java.security.Permission 型の XxxPermission 型オブジェクトを指定し、アクセスコントローラが権限チェックを行います。
リスト9 は、"fin をラップして、読み/書き/削除権限チェック perm で保護するガードオブジェクト guard を生成するものです。
リスト9. ガードオブジェクトの生成
FileInputStream fin = new FileInputStream("/tmp/guardDemo.txt");
FilePermission perm = new FilePermission("/tmp/guardDemo.txt", "read, write, delete");
GuardedObject guard = new GuardedObject(fin, perm);
このガードオブジェクト guard を受け取ったスレッドは、メソッド getObject() を使って保護対象のオブジェクトを取得します。このとき、内部的には、perm の checkPermission() を呼び出す Guard#checkGuard() が呼び出されます。
Object obj = guard.getObject();