2010-09-28 43 views
4

我試圖通過運行在非常嚴格的SecurityManager下處理用戶提供的內容的代碼來保護我的應用程序。它的AccessController.doPrivileged()開頭 - 通常這是用來提供額外的權限的代碼塊,但我用它來限制一個代碼塊到一個非常小的沙箱。在SecurityManager下創建對象時出現NoClassDefFoundError

一切都很好,直到我需要調用構造函數。然後我需要讀取世界。 (或者至少對我的類路徑中的所有.jar,.class和.property文件)。我不能只授予讀訪問權限,因爲這正是我想要避免的。 (例如,嘗試讀取/ etc/passwd的XEE攻擊)。我不認爲這足夠了。

我可以將一些構造函數移出SecurityManager塊,但有些是不可避免的,因爲它是一個SAX解析器,需要在它通過樹時創建對象。

想法?

+0

不知道我是否按照100%的方案,但它可能是問題不是構造函數,而是類加載(通常在給定類首次引用時發生)?如果是這樣,你可以簡單地在doPrivileged塊之外引用所需的類,並將構造函數留在其中。 – 2010-09-29 01:36:09

+0

不,它是每個構造函數。甚至像「新的String(foo)」的東西。 (我知道,愚蠢,但我試圖想出一些絕對有用的東西。) – bgiles 2010-10-05 21:06:22

回答

2

我找到了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內部的話,它們可能是安全的。如果來自用戶代碼,它們很可能會有問題。

相關問題