6

環境

コードが非常に厳密なサンドボックスで実行される Java システムを作成しています。クエリ (1 つ以上のクラスで構成される) は、その実行中に、1 つのフォルダー (およびフォルダー内に含まれるサブフォルダーとファイル) へのアクセスのみを許可する必要があります。

、およびクエリ実行ごとSecurityManagerに新しいを使用して、サンドボックスを強制します。usingでClassLoaderクラスを定義するときに、付与する必要があるファイル読み取り権限を含むを渡します。ClassLoaderdefineClassProtectionDomain

コール スタック上のすべてのオブジェクトが必要な特権を持っているわけではないため、クエリの読み取りアクションはAccessController.doPrivileged(...)-block 内で実行されます。

問題

  • AccessController.checkPermission(...)ブロック内から直接呼び出すと、doPrivileged(...)静かに返されます
  • System.getSecurityManager().checkPermission(...)にリクエストを転送する を呼び出すとAccessControllerAccessControllerは例外をスローします。
  • ?を介してProtectionDomain呼び出すと、 が失われるようです。AccessControllerSecurityManager
  • 制限されたファイル アクション ( の作成など) は、ではなくjava.io.FileReaderを直接呼び出します。ブロックを呼び出したクラスのを尊重するために、 を介して呼び出されたときに を取得するにはどうすればよいですか?SecurityManagerAccessControllerAccessControllerSecurityManagerProtectionDomaindoRestricted(...)
  • 自体にSecurityManager必要なアクセス許可がない可能性がありますか? これにより、特権コード間の呼び出しスタックに挟まれることで、AccessControllerどれも特権結合を生成しませんか?

以下にサンプル セクションを示します。

AccessController.doPrivileged(new PrivilegedAction<QueryResult>() {
  public QueryResult run() {
    String location = folderName + "/hello";
    FilePermission p = new FilePermission(location, "read");
    try {
      AccessController.checkPermission(p); // Doesn't raise an exception
      System.out.println("AccessController says OK");
      System.getSecurityManager().checkPermission(p);  // Raises AccessControlException
      System.out.println("SecurityManager says OK");
    } catch (AccessControlException e) {
      System.out.println("### Not allowed to read");
    }
    return null;
  }
});

スタック トレースの一部を含む、プログラムによって生成された出力 (使用される長いパス名を置き換える PATH):

AccessController says OK
Asked for permission: ("java.io.FilePermission" "PATH/hello" "read")
java.security.AccessControlException: access denied ("java.io.FilePermission" "PATH/hello" "read")
  at java.security.AccessControlContext.checkPermission(AccessControlContext.java:366)
  at java.security.AccessController.checkPermission(AccessController.java:560)
  at com.aircloak.cloak.security.CloakSecurityManager.checkPermission(CloakSecurityManager.java:40)
  at com.dummycorp.queries.ValidQuery$1.run(ValidQuery.java:23)
  at com.dummycorp.queries.ValidQuery$1.run(ValidQuery.java:1)
  at java.security.AccessController.doPrivileged(Native Method)
  at com.dummycorp.queries.ValidQuery.run(ValidQuery.java:16)
  at com.aircloak.cloak.security.CloakSecurityManagerTest$1.run(CloakSecurityManagerTest.java:75)
  at java.lang.Thread.run(Thread.java:722)

CloakAccessController.checkPermission(...)実装も興味深いかもしれません。次のようになります。

public void checkPermission(Permission perm) {
  if (Thread.currentThread().getId() == this.masterThread) {
    return;
  } else {
    System.out.println("Asked for permission: "+perm.toString());
  }
  AccessController.checkPermission(perm);
}

主に、それを作成したスレッドのセキュリティ制限をバイパスします。


私のjava.policyファイルの内容は、標準の MacOSX システムのものです。非標準的な変更は含まれていないと思います。

4

2 に答える 2

5

自分の質問に答えるのは少しぎこちない気がしますが、正しい解決策を見つけて、ここに追加するのが正しいと思うので、誰かがこの質問に遭遇した場合に備えて、将来のために文書化されています。

TL; DR

私のカスタムSecurityManagerには適切な権限がありませんでした。-blockを呼び出すクラスdoPrivileged(...)AccessControllerの間のコールスタック上にあったため、特権の共通部分はまったく特権ではありませんでした。

ロングバージョン

Javaセキュリティモデルは次のように機能します。AccessControllerは、クラスがメソッドの呼び出しを許可されているかどうかを確認するときに、コールスタックの上部から下部に向かってアクセス許可を調べます。コールスタックの各エントリに権限がある場合、アクションは許可されます。

これは、すべてが正常に機能する任意の例です。

+-----------+-------------------+-----------------------+
| Callstack | Class permissions | Permissions in effect |
+-----------+-------------------+-----------------------+
| Some      | {Read,Write}      | {Read}                |
| Other     | {Read}            | {Read}                |
+-----------+-------------------+-----------------------+

さて、私の質問の場合、コールスタックの下位層には権限がまったくありません。したがって、このような画像になりqueryます。上部には、実際には権限がありません。

+-----------+-------------------+-----------------------+
| Callstack | Class permissions | Permissions in effect |
+-----------+-------------------+-----------------------+
| Query     | {Read}            | {}                    |
| Other     | {}                | {}                    |
+-----------+-------------------+-----------------------+

doPrivileged(...)-blockを使用すると、この問題を回避できます。これにより、コールスタックを介した権限検索を、特権アクションを呼び出すエントリで終了できます。

+-----------+-------------------+-----------------------+
| Callstack | Class permissions | Permissions in effect |
+-----------+-------------------+-----------------------+
| Query     | {Read}            | {Read}                |
| Other     | {}                | {}                    |
+-----------+-------------------+-----------------------+

AccessController.checkPermission(...)これが、クエリ内からfromを呼び出したときにすべてが正常に機能した理由です。結局のところ、それは正しい許可を持っていました。(残念ながら)残念ながら、Java API(下位互換性のため)は常にSecurityManagerを呼び出します。私の場合、SecurityManagerには特権がまったくありませんでした。事実上、特権呼び出しを行うクエリとAccessControllerの間のコールスタック上にあったため、結果として得られる最終的なアクセス許可はありませんでした。

+-----------------+-------------------+-----------------------+
|    Callstack    | Class permissions | Permissions in effect |
+-----------------+-------------------+-----------------------+
| SecurityManager | {}                | {}                    |
| Query           | {Read}            | {Read}                |
| Other           | {}                | {}                    |
+-----------------+-------------------+-----------------------+

解決

解決策は、 SecurityManagerに基本的な権限セットを与えることでした。その結果、クエリに付与された権限は実際に必要なものでした。

+-----------------+---------------------+-----------------------+
|    Callstack    |  Class permissions  | Permissions in effect |
+-----------------+---------------------+-----------------------+
| SecurityManager | {Read,Write,Delete} | {Read}                |
| Query           | {Read}              | {Read}                |
| Other           | {}                  | {}                    |
+-----------------+---------------------+-----------------------+

ふぅ!それはかなり一口でした!これが誰かに役立つことを願っています:)

于 2012-12-12T08:59:19.553 に答える
1

ProtectionDomainここでの問題は、あなたが提供する方法にあると思いますSecurityManager

自分でクラスをロードし、SM を使用できるようにする場合は、SecureClassLoaderを拡張する必要があります。このクラスは、テンプレートを使用してメソッドを提供します。

protected Class defineClass(String name, byte[] b, int off, int len, CodeSource cs) 

クラスに を提供する必要がありますCodeSource。そして、他の方法:

   protected  PermissionCollection getPermissions(CodeSource codesource) 

指定されたCodeSourcePermissionCollectionからクラスを返します。これが、動的にロードされるクラスに動的アクセス許可を実装する方法です。

于 2012-12-11T18:40:35.197 に答える