CodeZine(コードジン)

特集ページ一覧

ビルド時にjava.policyをチェックすることで実行時エラーを回避する方法

java.policyをチェックして構文エラーを確認する簡単なユーティリティ

  • ブックマーク
  • LINEで送る
  • このエントリーをはてなブックマークに追加
2005/07/27 12:00

java.policyに構文エラーがあるかを確認するには、実行時まで待つしかないと思ってはいないでしょうか。ビルド時にjava.policyをチェックする簡単なツールを用いると、実行時に予想外の失敗が生じることを回避できます。

はじめに

 Javaのセキュリティ実装に変更が加えられたことで、セキュリティ機能が強化され、開発者がデフォルトのJavaセキュリティ機構にプログラム的なフックを追加できるようになりました。さらに、Java Authentication and Authorization Services(JAAS)が導入され、JDK 1.4のコアAPIに組み込まれたにもかかわらず、Javaのセキュリティは引き続き「java.security」と「java.policy」というコア設定ファイルの構造化テキスト形式に基づいています。XMLファイルの解析にはある程度のオーバーヘッドが付随することは広く知られていますが、「java.policy」におけるセキュリティの「grantブロック」は、非常に特異なレイアウトを採用しているため、ビルド時に構文的な検証をするための標準的なツールがありません。

 セキュリティ面でのニーズが低ければ、ポリシーファイルも単純で済み、担当チームも小規模なもので済むので、これが深刻な欠点として認識されることはないでしょう。しかし、複雑なセキュリティニーズを必要とする環境ならば、担当チームも大規模なものになり、「java.policy」ファイルに構文的なエラーが混入していても、実行時までそれに気づかない可能性があります。XMLファイルを利用するようPolicyクラスを拡張するという方法もありますが、たいていはSunのデフォルト実装だけに頼っているので、実行時に「java.policy」ファイル関連の問題が生じる可能性が残されます。

 こうした状況を受けて筆者が作成したのが、「java.policy」をチェックして、構文的なエラーがないかを報告するための簡単なユーティリティです。このユーティリティでは、各コードベースの指定パーミッションも出力できます。本稿では、このユーティリティのコードについて説明するほかに、ユーティリティの機能およびJava 2のセキュリティの基礎について簡単に紹介します。

必要な環境
 Java 1.3以上のバージョン。Sunによるとバージョン1.3は「役割を終えた」とのことなので、可能であれば1.4x以上のダウンロードをお勧めします。

 続きを読む前に、各自の「java.policy」および「java.security」ファイルを随時参照できるようにしておくと便利です。これらの2つのJava設定ファイルは、デフォルトで「${JAVA_HOME}/jre/lib/security」ディレクトリに置かれています。「security.policy」ファイルがパーミッション関連で果たす役割は、アプリケーションの参照するポリシーファイルを指定するというものです。ファイルURLに指定されるパーミッションは累積的なものであり、実行時にはアプリケーションに割り当てられるパーミッションの全リストが作成されます。デフォルトで指定されるURLは次の2つです。ポリシーファイルの位置についてはデフォルトのままにしておくのが無難ですが、変更できないわけではありません。

policy.url.1=file:${java.home}/lib/security/java.policy
policy.url.2=file:${user.home}/.java.policy

 代わりの位置はVM引数で指定できます。

Djava.security.manager=C:\your_policy_name.policy

 なお、policy.urlの機能を使うと複数のポリシーファイルを指定できますが、必要となるのは1つだけです。また、任意の名前を指定できます。

 「security.policy」ファイルは、標準のJavaプロパティファイルのように構造化されているので管理が比較的簡単であり、変更される頻度も「java.policy」ほどではありません。また設定の多くは、暗号プロバイダ、キーストアなどに関係するものです。こうしたものを開発者が変更する機会はそう多くないでしょう。

 「security.policy」の中で、「java.policy」へのプログラム的アクセスに関してもう1つ重要な意味を持つものとして、ポリシープロバイダの設定があります。これは、今回の検証ユーティリティが評価用のパーミッションを収集するときに最初にインスタンス化しなければならないクラスです。

policy.provider=sun.security.provider.PolicyFile

 Policyファイルオブジェクトを取得するには、通常は次のようなコードを使用します。

pcoll = Policy.getPolicy().getPermissions(cs);

 この呼び出しでは、Policyファイルオブジェクトを取得してから、関連するPermissionsCollectionを取得します。これについては、もう少し説明が必要です。

セキュリティマネージャ(Security Manager)のアクティブ化

 2つ目の設定ファイル「java.policy」の解説に入る前に、話は少しずれますが、デフォルトではJavaセキュリティはオンにならない、という点を指摘しておきたいと思います。今日では世界中で膨大な量のJavaコードが使われていますが、多くのJavaプログラマがこの点を知らないか、意識すらしていません。Java 2におけるすべてのセキュリティ機能は、SecurityManagerクラスで管理されており、このクラスはデフォルトで非アクティブにされています。SecurityManagerを使用するには2つの方法がありますが、その1つは実行時にコマンドラインで次のように指定することです。

java -Djava.security.manager

 2つ目はプログラム的にアクティブにする方法で、SecurityManagerをインスタンス化してから、これを明示的に呼び出し、目的とするアプリケーションのセキュリティチェックを実行させます。

 アプリケーションのセキュリティを確立する重要性は言うまでもないことですが、そのための機能をデフォルトでは非アクティブにしておくとしたSunの選択は、控え目に言っても残念なことです。意識的にセキュリティマネージャをオンにしないかぎり「java.policy」の設定はまったく生かされず、アプリケーションがAccessExceptionをスローすることもありません。こうしたJavaのセキュリティモデルについて多くの開発者が適切な知識を有してないということは、実際は安全ではないのに、自分のアプリケーションは安全だと思いこんでいる人間が多くいるということです。

grantブロックの設定

 ここで「java.policy」ファイルの説明に戻りますが、これはデフォルトのJava実行環境における2番目に重要なセキュリティ設定ファイルであり、パーミッションの設定もここで行います。Javaでは、特定のコードベース用に設定されるgrantブロックでパーミッションを設定します。たとえばSunから配布されるデフォルトの「java.policy」ファイルであれば、最初のgrantエントリは次のようになっています。

// Standard extensions get all permissions by default
grant codeBase "file:${java.home}/lib/ext/*" {
    permission java.security.AllPermission;
};

 このgrantエントリは、「/ext」ディレクトリ中のすべてのコードに、文字どおりすべてのパーミッションを許可します。このような状況を考えると、クラスパスの問題を解決する際に、クラスローディングのデリゲーションの階層を上げて「/ext」ディレクトリに入れるという手段を取るのは危険だと言われる理由がわかります。このディレクトリに所属するコードは、システムプロパティを修正する権利を有し、ファイルシステムに対して読み書きできるので、システム上であらゆる行為ができることになります。

 Sunの「コードベース」はURLとして指定されること、そしてアスタリスク記号(*)をワイルドカードとして使えることに注意してください。引用符、カッコ、末尾のセミコロン(;)を入れ忘れると、パーミッションファイルは解析できなくなり、実行時に正しく読み込まれなくなります(ビルド時にフォーマット検証を施しておこうというのは、こうした理由によります)。

 「java.policy」で指定するパーミッションはすべて同じ基本フォーマットに従いますが、たとえば次のサンプルのように、修飾子を追加することもできます。

// com.tillman.util.security.permissionchecker package is in this directory
grant codeBase "file:/C:/eclipse/workspace/Permissions/PermissionReader/bin/*" {
    permission java.security.SecurityPermission "getPolicy";
    permission java.io.FilePermission "<<ALL FILES>>", "read,write,execute,delete";
    permission java.net.URLPermission "http://www.nytimes.com", "listen, connect";
};

 今回の検証ユーティリティはPolicyオブジェクトへの参照を取得してパーミッションをチェックする必要があるので、上記のブロックにある最初のパーミッションは必須であり、ポリシーファイルで明示的に指定しておく必要があります。また、言うまでもありませんが、検証ユーティリティの所在位置を示すファイルURLについては、該当する情報に各自修正する必要があります。

 パーミッションの検証コードは、基本的に単純な構造をしています。唯一複雑なのは、検証対象とするコードベースをプロパティファイル中で指定できるようにした部分です。これにより、デフォルトのgrantブロックを無視できるようになります(ただし結果の出力には、指定したパーミッションだけでなく、これらのデフォルトブロックについても出力されます)。検証用コードにあるgetFileLocations()メソッドは、プロパティファイルで指定されたコードベースのリストを返すだけのものです(Windows上では、バックスラッシュ記号をエスケープする必要があるので、二重のバックスラッシュを使用します)。

 whileループでは、プロパティファイルに指定された個々のロケーションをコードベースのURLに変換しています。

codebase = new File((String)iter.next()).toURL();

 その後、各々のコードベースは、CodeSourceコンストラクタに引数として渡されます。実質的にCodeSourceは、PolicyオブジェクトがPermissionCollectionを取得するための「キー」として機能します。

cs = new CodeSource(codebase, null);
pcoll = Policy.getPolicy().getPermissions(cs);

 PermissionCollection型であるpcoll変数のメンバは、elements()メソッドを用いて列挙値として返されます。そして最後に、すべての列挙値を反復処理し、取得された各PermissionオブジェクトのtoString()メソッドを用いて、該当する名前を出力します。

enum1 = pcoll.elements();
for (; enum1.hasMoreElements(); ) {
            System.out.println((Object)enum1.nextElement());
}

 得られた結果は、次のような形式で出力されます。

path: /C:/eclipse/workspace/Permissions/TestTwo/bin
(java.util.PropertyPermission java.version read)
(java.util.PropertyPermission java.vm.name read)

 パーミッションのgrantブロックの構文、あるいはパーミッションそのものに何らかのエラーがあった場合、このユーティリティは解析エラーに関するメッセージを表示します。実際には、Policyオブジェクトの取得要求は、コードの残りを実行することなく終了します。とは言うものの、このユーティリティで得られる、各々のコードベースのパーミッションを収集したリストは、自分が実装したセキュリティが想定どおりになっているかを確認する際に有用な情報となるはずです。

 いったんSecurityManagerをアクティブにしてしまえば、Java 2の持つ柔軟かつ強力なセキュリティ機能を自由に使用することができます。「java.policy」と「java.security」ファイルは、もしかしたらXMLファイル形式として実装した方が便利なのかもしれませんが、現在の方法にも、可読性と管理性の点で優れているという長所があります。さらに、ここで見たように「java.policy」ファイルは、ビルド時にチェックを施すことで、実行時に想定外のセキュリティエラーが生じるのを避けることができます。JavaのPolicyオブジェクトは、必要に応じて動作を拡張することもできますが、標準の設定オプションだけでもたいていのセキュリティ要件は満たせるはずです。



  • ブックマーク
  • LINEで送る
  • このエントリーをはてなブックマークに追加

あなたにオススメ

著者プロフィール

  • Doug Tillman(Doug Tillman)

    Grainger.comで活躍するベテランのJavaおよびPython開発者。開発者の役に立つツールを作成することに強い関心を持ち、積極的に取り組んでいる。

  • japan.internet.com(ジャパンインターネットコム)

    japan.internet.com は、1999年9月にオープンした、日本初のネットビジネス専門ニュースサイト。月間2億以上のページビューを誇る米国 Jupitermedia Corporation (Nasdaq: JUPM) のニュースサイト internet.com や EarthWeb.c...

バックナンバー

連載:japan.internet.com翻訳記事

もっと読む

All contents copyright © 2005-2021 Shoeisha Co., Ltd. All rights reserved. ver.1.5