在SecurityManager下创建对象时出现NoClassDefFoundError

发布于 2024-09-25 07:13:10 字数 400 浏览 4 评论 0原文

我试图通过在非常严格的 SecurityManager 下运行处理用户提供的内容的代码来保护我的应用程序。它是 AccessController.doPrivileged() 的本质——通常这用于提供具有额外权限的代码块,但我使用它来将代码块限制在一个非常小的沙箱中。

一切都很好,直到我需要调用构造函数。然后我需要对世界进行读取访问。 (或者至少是我的类路径上的所有 .jar、.class 和 .property 文件。)我不能只授予对 <> 的读取访问权限。因为这就是我试图避免的。 (例如,试图读取 /etc/passwd 的 XEE 攻击。)我认为这还不够。

我可以将一些构造函数移出 SecurityManager 块,但有些构造函数是不可避免的,因为它是一个 SAX 解析器,需要在遍历树时创建对象。

有想法吗?

I'm trying to secure my application by running the bits of code that deal with user-provided content under a very restrictive SecurityManager. It's AccessController.doPrivileged() turned on its head - normally this is used to provide a block of code with extra permissions but I'm using it to constrain a block of code to a very small sandbox.

Everything is fine until I need to call a constructor. Then I need read-access to the world. (Or at least to all of the .jar, .class and .property files on my classpath.) I can't just grant read access to <> since that's what I'm trying to avoid. (E.g., an XEE attack that tries to read /etc/passwd.) I don't think that would be enough anyway.

I can move some of the constructors out of the SecurityManager block, but some are unavoidable since it's a SAX parser that needs to create objects as it goes through the tree.

Ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

薄凉少年不暖心 2024-10-02 07:13:10

我找到了90%的答案。简而言之,我们需要设置很多权限,但过程很明显并且很容易隐藏在某些实用程序类中。如果它可以在标准的地方使用那就太好了,但是哦,好吧。 叹息。

我们需要做的就是检查类路径和ext dir的系统属性(并为它们添加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"));
    }
}

少了一点可怕。这些权限为大规模破坏打开了大门。

    // ------------ 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 方法,并在看到前两个权限(至少)时查看调用堆栈。如果它们来自 JDK 的深处,那么它们可能是安全的。如果来自用户代码,它们可能是不确定的。

I found a 90% answer. The short answer is that we need to set up a lot of permissions but the process is obvious and easy to hide in some utility class. It would be nice if it were available somewhere standard, but oh well. le sigh.

All we need to do is check system properties for the classpath and ext dir (and add FilePermissions (read-only) for them), make the necessary SecurityPermissions (read-only), and finally add PropertyPermissions (read-only) for all system properties. All that's left is a handful of really obvious permissions, e.g., granting r/w/d (but not execute) permission to the temp directory, granting 'resolve' access to localhost, etc.

A really secure sandbox may not want to make all of the system properties readable but that's easily fixed and is left to the reader.

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"));
    }
}

There's one scary bit less. These permissions open the door to massive havoc.

    // ------------ 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 -----------

I haven't decided on the best course of action here. I think what I may do is override the checkPermission method and look at the call stack when the first two permissions (at least) are seen. They're probably safe if they're coming from deep within the JDK. They're probably iffy if coming from the user code.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文