9

SecurityManagerを使用する場合、パフォーマンスが低下しますか?

私は以下が必要です:

public class ExitHelper {

    public ExitHelper() {

        System.setSecurityManager(new ExitMonitorSecurityManager());

    }

    private static class ExitMonitorSecurityManager extends SecurityManager {

        @Override
        public void checkPermission(Permission perm) {}

        @Override
        public void checkPermission(Permission perm, Object context) {}

        @Override
        public void checkExit( final int status ) {
            // this is the part I need and I don't care much about the performance issue of this method
        }
}

これは私のプログラムに大きな影響を与えますか?

たとえば、プログラムは多くのファイルを開きます。また、SecurityManagerを有効にしてそこにログインすると、これらのメソッドが頻繁に呼び出される可能性があります。本当にたくさん。これらの2つの方法からのロギングでは、通常のロギングが失われるほどです。したがって、SecurityManagerを配置するということは、多くの呼び出しが行われることを意味しているようです。デフォルトのSecurityManagerよりも遅くなりますか?(デフォルトで何かありますか?)

これはどのように作動しますか?プログラムのどの部分で権限がチェックされ、どのくらいの頻度でチェックされますか?私は2つのcheckPermission(...)メソッドに関心があります。

4

3 に答える 3

7

パフォーマンスの低下がありますが、次の理由で小さい可能性があります。

  • これは、許可チェックを必要とする何らかの形式のアクティビティを試みる場合にのみ適用されます。
  • 権限チェックを必要とするほとんどの操作はコストのかかる操作(IO、ネットワークアクセスなど)であるため、セキュリティチェックのオーバーヘッドは総実行時間のかなり低い割合になる可能性があります。
  • チェック自体は非常に安く作ることができます

特に、セキュリティチェックの呼び出しコードは、通常、Javaライブラリコードでは非常に軽量であることに注意してください。つまり、次のようになります。

 SecurityManager security = System.getSecurityManager();
 if (security != null) {
     security.checkXXX(argument,  . . . );
 }

セキュリティマネージャのコード自体も同様に軽量である場合、セキュリティチェックの実行時のコストはごくわずかです。ただし、SecurityManager自体にロギングコードを配置することは避けます。これはコストがかかり、アプリケーションコードの上位レベルに属する可能性があります。

気にしないアクセス許可のセキュリティマネージャのオーバーヘッドを完全に最小限に抑えたい場合は、不要な特定のcheckXXXメソッドを次のようにオーバーライドする必要があります。

@Override 
public void checkRead(String file) {
  // empty method as we are happy to allow all file reads
}

最終的には、特定の状況についてベンチマークを行う必要がありますが、「直感」の答えは、実際にはそれについて心配する必要はないということです。

于 2011-11-22T18:00:10.940 に答える
2

はい、パフォーマンスの低下があります。あなたがそれを心配しているなら、あなたの唯一の頼みはそれを測定し、ペナルティが高すぎるかどうかを見ることです。

特定のユースケースに対する1つの潜在的な解決策は、必要なときに範囲を狭めることができるかどうかです。制御できないコードがアプリケーションを終了するのを明らかに止めたいと考えています。そのコードがいつ呼び出されるかがわかっている場合は、その呼び出し中にセキュリティマネージャーを設定するだけです(セキュリティマネージャーの設定はグローバルであるため、ここではスレッドの影響に注意する必要があります)。例:

System.setSecurityManager(new ExitMonitorSecurityManager());
try {
  // ... do protected op here ...
} finally {
  System.setSecurityManager(null);
}

アップデート:

後でこの回答にたどり着く可能性のある人に明確にするために、この回答は潜在的に悪意のあるコードを処理するようには設計されていません。そのような状況では、適切に構成されたSecurityManagerを常に配置する必要があります。この回答は、OPが、明確に定義された時点でSystem.exit()を不幸に呼び出す、記述が不十分なサードパーティライブラリを処理しようとしていることを前提としています。

于 2011-11-22T17:36:34.083 に答える
2

セキュリティマネージャーの質問を実装した後、ここで貢献するいくつかの経験的証拠があります。

System.exitの単一のチェック調整を除いてNOセキュリティマネージャーと同一のJavaSecurityManager

この匿名の内部クラスによるパフォーマンスへの影響は非常に大きかった。

        System.setSecurityManager(new SecurityManager() {
            @Override
            public void checkPermission(Permission perm) {
                return; // no security manager behaviour
            }

            @Override
            public void checkPermission(Permission perm, Object context) {
                return; // no security manager behaviour
            }

            @Override
            public void checkExit(int status) {
                Thread.dumpStack();
                super.checkExit(status);
            }
        });

Eclipseでアプリケーションを起動した後の私の経験では、アプリケーションの速度が明らかに遅く、同僚のPCでも同じことを確認しました。

したがって、「無視できる」というのは控えめな表現かもしれないと思います(そして、私のユースケースは実際にはチェックを実行しません!)。これは、そうではないという逸話と考えてください。

別の補足として:パーミッションオブジェクトなどのインスタンス化を回避するために、ALLメソッドに対して何もしないチェックを使用して最終クラスを作成しました(最後に、jitコンパイラにホットワイヤーを使用するように促します)。このアプローチを使用すると、パフォーマンスへの影響は実際に最小限に抑えられました。したがって、単にいくつかの特定のチェックを追加したい(そしてJavaポリシーに依存しない)人にとって、これは実際には無視できるほどの影響しかありません。

public final class SystemExitTraceSecurityManager extends SecurityManager {

    @Override
    public final void checkAccept(String host, int port) {
    }

    @Override
    public final void checkAccess(Thread t) {
    }

    @Override
    public final void checkAccess(ThreadGroup g) {
    }

    @Override
    public final void checkAwtEventQueueAccess() {
    }

    @Override
    public final void checkConnect(String host, int port) {
    }

    @Override
    public final void checkConnect(String host, int port, Object context) {
    }

    @Override
    public final void checkCreateClassLoader() {
    }

    public final void checkDelete(String file) {
    };

    @Override
    public final void checkExec(String cmd) {
    }

    public final void checkExit(int status) {
        Thread.dumpStack();
    };

    @Override
    public final void checkLink(String lib) {
    }

    @Override
    public final void checkListen(int port) {
    }

    @Override
    public final void checkMemberAccess(Class<?> clazz, int which) {
    }

    @Override
    public final void checkMulticast(InetAddress maddr) {
    }

    @Override
    public final void checkMulticast(InetAddress maddr, byte ttl) {
    }

    @Override
    public final void checkPackageAccess(String pkg) {
    }

    @Override
    public final void checkPackageDefinition(String pkg) {
    }

    @Override
    public final void checkPermission(Permission perm) {
    }

    @Override
    public final void checkPermission(Permission perm, Object context) {
    }

    @Override
    public final void checkPrintJobAccess() {
    }

    @Override
    public final void checkPropertiesAccess() {
    }

    public final void checkPropertyAccess(String key) {
    };

    @Override
    public final void checkRead(FileDescriptor fd) {
    }

    @Override
    public final void checkRead(String file) {
    }

    @Override
    public final void checkRead(String file, Object context) {
    }

    @Override
    public final void checkSecurityAccess(String target) {
    }

    @Override
    public final void checkSetFactory() {
    }

    @Override
    public final void checkSystemClipboardAccess() {
    }

    @Override
    public final boolean checkTopLevelWindow(Object window) {
        return true;
    }

    @Override
    public final void checkWrite(FileDescriptor fd) {
    }

    @Override
    public final void checkWrite(String file) {
    }
}
于 2017-08-31T09:07:01.830 に答える