seraphyの日記

日記というよりは過去を振り返るときのための単なる備忘録

JAVAセキュリティメカニズムのメモ

セキュリティマネージャとポリシーの設定

★ 関連記事あります:
自作Javaアプリにサンドボックスで動くアドインの仕組みを作る方法 (2018/6/12追記)

  • System.getSecurityManager()がnullの場合、セキュリティメカニズムは機能しない。つまり、どのようなセキュリティポリシーであれ、それは全く検証されず全権で動作する。*1
  • 一部でもセキュリティメカニズムを使いたい場合は、セキュリティマネージャを有効にする必要がある。
  • セキュリティポリシーはPolicyクラスによって保持される。
    • Policyは、システムプロパティ「-Djava.security.policy=XXXX.policy」のように指定してポリシーファイルを読み込むことができる。
    • 明示的にPolicyを作成する場合、PolicyクラスはAbstractであるが全てのメソッドが実装済みのテンプレートクラスとなっている。getPermissions(CodeSource)をオーバーライドしてコードソースに対応するパーミッションコレクションを返せばよい。
  • ポリシーは、コードソースに対するパーミッションコレクションの集合である。
  • 全てのパーミッションは許可を示す。拒否を示すことはできない。権限が存在しないことが拒否を表す。全権があることを示すには、AllPermissionクラスを用いる。
    • ポリシーで有効な権限が1つもなければ、それがサンドボックスを意味する。
    • パーミッションは追加できるが削除できない。ClassLoaderは、クラスをロードするときにプロテクションドメイン(ProtectionDomain)に対して権限を追加しマージすることができる。しかし、すでに付与されている権限を減ずることはできない。
      • クラスがすでにロードされている場合、そのプロテクションドメインは不変である。もはやパーミッションを変更することはできない。
      • つまり、アプリケーションコードの中でアプリケーション自身のパーミッションを設定しようと思っても手おくれである。可能なのは、新しいクラスローダが、これからロードするクラスに対して、追加の権限を与えることだけである。

コードソース(Codesource)の役割

  • すべてのクラスはコードソースをもっている。
    • コードソースは、クラスの実体が置かれているロケーションと、そのコードの署名をもっている。ロケーションは、ローカルシステム上のアプリケーションであればファイルシステムの位置を表すURLであり、それが署名付きJARであれば、それが署名も保持する。(署名がなければnull)。このペアがコードソースである。
    • 実行中のクラスのコードソースは、Class#getProtectionDomain()からProtectionDomain#getCodeSource()で取得可能である。
  • コードソースに対するパーミッションコレクションのペアがプロテクションドメイン(ProtectionDomain)である。
      • nullクラスローダから読み込まれるシステムクラスのプロテクションドメインでは、コードソースを持たずnullとなるが、パーミッションコレクションは有効であり、全権があてられている。
  • セキュリティポリシーでは、そのコードソースに対して権限を割り当てる。
    • つまり、明示的に指定された特定の場所にあるコードのみが特定の権限をもち、それに該当しない場合は、すべてサンドボックス上で動作する。
  • パーミッションの検査は、現在実行されている呼び出し履歴の中の、すべてのコードソースで許可される場合のみ許可される。いいかえると、呼び出し履歴の中の、もっとも低い権限で実行される。

特権(AccessController.doPrivileged)の意味

  • 権限の低いレベルのコードソースが、権限の高いレベルのコードソースを呼び出した場合には、呼び出し履歴の規則によって、高いレベルのコードソースであっても権限は低いほうに限定される。
  • 低いレベルから高いレベルのコードソースが呼び出された場合でも、そのコードソースがもっている権限を行使したい場合に「特権」を行使する。つまり、呼び出し元がどうであれ、本来、自分がもっている権限で実行したい場合が「特権」の意味である。
    • つまり、ライブラリなど外部から利用される可能性があるコードにおいて、そのコードがセキュリティ上の権限を必要とする操作を行う場合には、特権コードとして実行するように記述しておかないと、実行時にセキュリティが足りない事態になる可能性がある。
      • 逆に特権を行為する特別な意図がなければ、単に特権を明示しなければ最小限の権限で動作できる。
    • 特権を指定しても、本来、そのコードソースが許可されている以上の権限は行使できない。

結論

サンドボックスを実装するために必要なコードは0行である。つーか、コードでサンドボックスを書くことは無理。諦めれ。*2
URLClassLoaderを使ってアプリケーションから読みこむアドインにセキュリティをかけたい場合には単に、自分以外のコードソースに権限を与えないようなポリシーを読ませておけば、それで十分。それ以上やる意味なし。

*1:自前のコードに限っていえばSecurityManagerを使わずAccessControllerを使ってセキュリティチェックすることは可能である。しかし、システムクラスは、そのような実装になっていないし、アプリケーションの書き方としても推奨されていない。

*2:JSE6の新しいブートストラップのメカニズムを使ったり、WASやSJSASといったJ2EEサーバのような、もっと手のこんだ方法を考えればいけるのかもしれないが、もう、やる気が起きない。できたとしても、多分、割に合わない。標準のメカニズムで十分だ。