TomcatにおけるJava SecurityManagerの使用方法

なぜSecurityManagerを使うのでしょう?

信頼できないコードがローカルシステム上のファイルにアクセスしたり、 Appletが、それがロードされた以外のホストに接続するのを防止するために、 JavaのSecurityManagerは,Appletをブラウザのサンドボックス内で実行させ ます。

SecurityManagerがブラウザで信頼できないAppletが実行されないように保護 するように、Tomcatの実行中に、SecurityManagerを使ってトロイの木馬的な Servletや、JSP、JSP beans、タグライブラリからサーバを保護することが できます。さらに、不注意によるミスからも同様に保護することができます。

あなたのサイトで、うっかり以下のようなコードを含むJSPの登録を認めたこ とを想像してみてください。

<% System.exit(1); %>


このJSPがTomcatで実行されると,Tomcatは常にExitしてしまいます。

JavaのSecurityManagerを使うことは,システム管理者がサーバーを安全で信 頼できる状態を保つために使用できる一つの防御ラインです。

システム要求条件

SecurityManagerを使うには、JDK1.2をサポートするJVMが必要です。
 

注意

TomcatにおけるSecurityManagerの実装は、Tomcatのセキュリティを確実にす るほどには充分にテストされていません。JSPや、Webアプリケーション、 Servlet、bean、タグライブラリがTomcatの内部のクラスにアクセスしないよ うにするためのパーミッションも追加されていません。信頼できないユーザが Webアプリケーションや、JSP、Servlet、beans、タグライブラリを登録するこ とを認める前に、SecurityManagerの設定が充分かどうかを確認してください。

それでも、SecurityManagerを使って運用する方が、それを使わないで運用す るよりも確実に安全です。
 

パーミッションの種類

Permissionクラスは、Tomcatがロードするクラスがどのパーミッションを持つ かを定義するために使われます。多くのPermissionクラスがJDKに含まれてい ます。そして、あなた自身のWebアプリケーションのために、専用のPermission クラスを作ることもできます。

Tomcatに適用できるシステムのSecurityManagerのPermissionクラスを、以下 に簡単に説明します。  パーミッションの使用方法については、JDKのドキュ メントを参照してください。

java.util.PropertyPermission
    java.home のようなJVMプロパティへのread/writeアクセスの制御

java.lang.RuntimePermission
    exit()やexec()のようなシステム/ランタイム関数の制御

java.io.FilePermission
    ファイルとディレクトリに対するread/write/executeアクセスの制御

java.net.SocketPermission
    ネットワークのソケットの使用の制御

java.net.NetPermission
    マルチキャストネットワークコネクションの使用の制御

java.lang.reflect.ReflectPermission
    クラスを内省するために使用するリフレクションの使用の制御

java.security.SecurityPermission
    Securityメソッドへのアクセスの制御

java.security.AllPermission
    SecurityManagerを使わずにTomcatを実行しているように、全てのパーミッショ ンに対してアクセスを許可します。
 

SecurityManagerを使ったTomcatの設定

tomcat.policy

Java SecurityManagerによって実現されるセキュリティポリシーはtomcatのconfディレクトリの tomcat.policyファイルで設定されます。  tomcat.policyファイルは常にシステムのjava.policyファイルを置き換えます。  tomcat.policyファイルは自分の手で編集することもできるし、Java1.2ではpolicytoolアプ リケーションを使って編集することもできます。

tomcat.policyファイルのエントリは、標準のjava.policyファイルのフォーマットに準じています。
// policyファイルエントリの例

grant [signedBy <signer> [,codeBase <code source>] {
    permission <class> [<name> [, <action list>]];
};
signedBycodeBaseエントリはパーミッションを与える時のオプションです。 コメント行は //で始まり、行末で終わります。

codeBase はURLフォームやfile URLで、定義したディレクトリパスを展開する${java.home}や ${tomcat.home}プロパティを使うことができます。

デフォルトの tomcat.policy ファイル
// Tomcatのパーミッション

// javacにはこれが必要
grant codeBase "file:${java.home}/lib/-" {
  permission java.security.AllPermission;
};

// Tomcatは全てのパーミッションを取得します
grant codeBase "file:${tomcat.home}/lib/-" {
  permission java.security.AllPermission;
};

grant codeBase "file:${tomcat.home}/classes/-" {
  permission java.security.AllPermission;
};

// webappポリシーの例
// デフォルトではwebappディレクトリはreadアクセスとline.separatorのreadが
// 許可されたPropertyPermissionです。
grant codeBase "file:${tomcat.home}/webapps/examples" {
  permission java.net.SocketPermission "localhost:1024-","listen";
  permission java.util.PropertyPermission "*","read";
};

これは、上に加えてメールを送ることができるようにlocalhost smtpポートに 接続する能力をウェブアプリケーションに与える例です。
grant codeBase "file:${tomcat.home}/webapps/examples" {
  permission java.net.SocketPermission "localhost:25","connect";
  permission java.net.SocketPermission "localhost:1024","listen";
  permission java.util.PropertyPermission "*","read";
};
定義されていない全てのコンテキストに与えたい場合、Tomcatがデフォルトで割り 当てるいくつかのデフォルト許可をエントリに加えます。
grant {
  permission java.net.SocketPermission "localhost:1024","listen";
  permission java.util.PropertyPermission "*","read";
};
最終的にはより複雑なtomcat.policyファイルになります。 この場合、多くのリモートウェブサーバにappサーバとしてTomcatを使用しています。 リモートウェブサーバがJava SecurityManagerを使用することによってTomcatに接続 することができることを制限したいと思います。
 
// Tomcatのパーミッション
// jacacはこれを必要とします。
grant codeBase "file:${java.home}/lib/-" {
  permission java.security.AllPermission;
};

// IPフィルタリングを行うTomcat
grant codeBase "file:${tomcat.home}/lib/-" {
  // Tomcatは全プロパティをread/write出来なければなりません。
  permission java.util.PropertyPermission "*","read,write";
  // Tomcatは自分自身のディレクトリのファイルは読めなければなりません。
  permission java.io.FilePermission "${tomcat.home}/-","read";
  // Tomcatはログを書きこめなければなりません。
  permission java.io.FilePermission "${tomcat.home}/logs/-","read,write";
  // Tomcatはconfディレクトリに書きこめなければなりません。
  permission java.io.FilePermission "${tomcat.home}/conf/-","read,write";
  // TomcatはJSPがコンパイルできなければなりません。
  permission java.io.FilePermission "${tomcat.home}/work/-","read,write,delete";
  // Tomcatは全RuntimePermissionが必要です。
  permission java.lang.RuntimePermission "*";
  // Tomcatはコンテキストにセキュリティポリシーをセットできる必要があります。
  permission java.security.SecurityPermission "*";
  // Tomcatはリモートウェブサーバからの接続を受け付ける必要があります。
  // XXX.XXX.XXX.XXXをリモートウェブサーバのIPアドレスで置き換えてください。
  permission java.net.SocketPermission "XXX.XXX.XXX.XXX:1024-","accept,listen,resolve";
  // Tomcatはlocalhostでそのポートを使用することができなければなりません。
  permission java.net.SocketPermission "localhost:1024-","connect,accept,listen,resolve";
};

// webappポリシーの例
// デフォルトではwebappディレクトリはreadアクセスとline.separatorのreadが
// 許可されたPropertyPermissionです。
grant codeBase "file:${tomcat.home}/webapps/examples" {
  permission java.net.SocketPermission "localhost:1024-","listen";
  permission java.util.PropertyPermission "*","read";
};

server.xml

PolicyInterceptorクラスを定義するContextInterceptorのためにserver.xmlでのエントリをコメントから復帰させてください
 

SecurityManagerを有効にするTomcatの起動方法

一旦あなたがSecurityManagerを使用するように、tomcat.policyとserver.xml ファイルを設定してしまえば、bin/startup.bat や bin/startup.shに "-security"オプションを指定することで、SecurityManagerを使用するように Tomcatを起動することができます。
 

SecurityManagerがSecurity違反を検出したとき、何が起こるのでしょう?

SecurityManagerがセキュリティポリシーの違反を検出したときには、JVMは AccessControlExceptionまたはSecurityExceptionをthrowします。
 

tomcat.policyの設定とセキュリティ違反のトラブルシューティング

JVMの内部のjavacを使用するJSPコンパイルがaccessClassInPackageであるsun.tools.javacに RuntimePermissionを付けたためにAccessControlExceptionで失敗します。

JAVA_HOME/jre/lib/security/java.securityファイルの設定をチェックしてください。  "package.access=sun."の行をコメントアウトしてください。

JVMの内部のjavacを使用するJSPコンパイルがTomcatのworkディレクトリにreadのFilePermission を付けたためにAccessControlExceptionで失敗します。

codeBaseが必要とするjavaへのポリシー許可に${java.home}で指定しているものの代わりに絶対パスを設定してみてください。

// jacacはこれを必要とします。
grant codeBase "file:/usr/java/lib/-" {
  permission java.security.AllPermission;
};

 

[訳注: これは角瀬和博が翻訳しました。 日本語訳に対するコメントは、jajakarta-report@nekoyanagi.com宛に送って下さい。]