4

非常に制限の厳しい SecurityManager の下でユーザー提供のコンテンツを処理するコードを実行することで、アプリケーションを保護しようとしています。それは AccessController.doPrivileged() の頭をオンにしたものです。通常、これはコードのブロックに追加のアクセス許可を提供するために使用されますが、コードのブロックを非常に小さなサンドボックスに制限するために使用しています。

コンストラクターを呼び出す必要があるまでは、すべて問題ありません。次に、世界への読み取りアクセスが必要です。(または、少なくともクラスパス上のすべての .jar、.class、および .property ファイルに。) <> への読み取りアクセスを許可することはできません。それは私が避けようとしていることだからです。(たとえば、/etc/passwd を読み込もうとする XEE 攻撃。)とにかく、それだけでは十分ではないと思います。

一部のコンストラクターを SecurityManager ブロックの外に移動できますが、ツリーを通過するときにオブジェクトを作成する必要があるのは SAX パーサーであるため、避けられないものもあります。

アイデア?

4

1 に答える 1

2

私は90%の答えを見つけました。簡単に言うと、多くの権限を設定する必要がありますが、そのプロセスは明白で、一部のユーティリティクラスでは簡単に隠すことができます。それがどこか標準的な場所で利用可能であるならそれは素晴らしいでしょう、しかしまあ。 ルため息。

クラスパスとextdirのシステムプロパティを確認し(そしてそれらにFilePermissions(読み取り専用)を追加し)、必要なSecurityPermissions(読み取り専用)を作成し、最後にすべてのシステムにPropertyPermissions(読み取り専用)を追加するだけです。プロパティ。残っているのは、いくつかの本当に明白な権限です。たとえば、一時ディレクトリへのr / w / d(実行はしない)権限の付与、ローカルホストへの「解決」アクセスの付与などです。

本当に安全なサンドボックスは、すべてのシステムプロパティを読みやすくしたくない場合がありますが、それは簡単に修正でき、読者に任されています。

public class LoggingSecurityManager extends SecurityManager {
    private AccessControlContext ctx;
    private Properties properties = new Properties;
    private Set missingProperties = new HashSet();

    public LoggingSecurityManager() {
        properties.add(
            new FilePermission(System.get("java.io.tmpdir") + "/-", "read,write,delete"));

        // maybe...
        properties.add(
            new FilePermission(System.get("user.home") + "/-", "read,write,delete"));

        addSystemPropertyPermissions();
        addSecurityPermissions();
        addClassPathPermissions();
        addOtherPropertyPermissions();

        permissions.add(new RuntimePermission("accessClassInPackage.sun.reflect"));
        permissions.add(new RuntimePermission("accessClassInPackage.sun.jdbc.odbc"));
        permissions.add(new RuntimePermission("accessClassInPackage.sun.security.provider"));
        permissions.add(new SocketPermission("localhost", "resolve"));
        permissions.add(new NetPermission("getProxySelector"));

        ctx = new AccessControlContext(new ProtectionDomain[] {
            new ProtectionDomain(null, permissions)
        });
    }

    /**
     * Add read-only permission to read system properties.
     * We may want to filter this list to remove sensitive information
     */
    public void addSystemPropertyPermissions() {
        for (Object key : Collections.list(System.getProperties().keys())) {
            permissions.add(new PropertyPermission((String) key, "read"));
        }
    }

    /**
     * Add read-only permissions for initializing security.
     */
    public void addSecurityPermissions() {
        permissions.add(new SecurityPermission("getPolicy"));
        permissions.add(new SecurityPermission("getProperty.random.source"));
        permissions.add(new SecurityPermission("getProperty.securerandom.source"));

        for (int i = 1; i < 10; i++) { // configurable limit?
            permissions.add(new SecurityPermission("getProperty.security.provider." + i));
        }

        String s = Security.getProperty("securerandom.source");
        if ((s != null) && s.startsWith("file:/")) {
            permissions.add(new FilePermission(s.substring(5), "read"));
        }

        // should have been covered already but wasn't....
        permissions.add(new FilePermission("/dev/random", "read"));
      }

    /**
     * Add read-only permissions for everything on classpath.
     */
    public void addClassPathPermissions() {
        permissions.add(new FilePermission(String.format("%/lib/-",
            System.getProperty("java.home")), "read"));

        // add standard class path.
        String pathSep = System.getProperty("path.separator");
        for (String entry : System.getProperty("java.class.path").split(pathSep)) {
            File f = new File(entry);
            if (f.isFile()) {
                permissions.add(new FilePermission(entry, "read"));
            } else if (f.isDirectory()) {
                permissions.add(new FilePermission(String.format("%s/-", entry), "read"));
            } // or could be neither fish nor fowl
        }

        // add endorsed extensions.
        for (String dir : System.getProperty("java.ext.dirs").split(pathSep)) {
            permissions.add(new FilePermission(String.format("%s/-", dir), "read"));
        }
    }

    /**
     * Add other standard properties.
     */
    public void addOtherPropertyPermissions() {
        permissions.add(new PropertyPermission("jdbc.drivers", "read"));
        permissions.add(new PropertyPermission("java.security.egd", "read"));
        permissions.add(new PropertyPermission("socksProxyHost", "read"));
    }
}

怖いものが1つ少なくなります。これらの許可は、大混乱への扉を開きます。

    // ------------ S C A R Y - B L O C K -----------
    permissions.add(new ReflectPermission("suppressAccessChecks"));  (!!)
    permissions.add(new RuntimePermission("createClassLoader")); (!!)
    permissions.add(new SecurityPermission("putProviderProperty.SUN"));
    permissions.add(new RuntimePermission("readFileDescriptor"));**
    permissions.add(new RuntimePermission("writeFileDescriptor"));
    // ------------ S C A R Y - B L O C K -----------

私はここで最善の行動方針を決定していません。私ができることは、checkPermissionメソッドをオーバーライドし、(少なくとも)最初の2つのアクセス許可が表示されたときに呼び出しスタックを確認することだと思います。JDKの奥深くから来ている場合は、おそらく安全です。ユーザーコードから来た場合、それらはおそらく気難しいでしょう。

于 2010-10-06T14:46:52.580 に答える