java安全沙箱(四)之安全管理器及Java API

java是一種類型安全的語言,它有四類稱爲安全沙箱機制的安全機制來保證語言的安全性,這四類安全沙箱分別是:java

本篇博客主要介紹「類安全管理器及Java API」的基本原理,如需瞭解其它幾類安全機制能夠經過上面的博客連接進入查看app

簡介

java安全沙箱的前三類保證了jvm所運行程序的完整性,使得jvm不會由於運行有漏洞或惡意的代碼而致使出現不可預期的狀態。而第四類沙箱模型是「類安全管理器及Java API」,它能保護jvm在運行有漏洞或惡意的代碼不會破壞外部資源。java經過稱爲安全管理器的一類API來保證這類安全性。jvm

安全策略文件

首先介紹下安全策略文件,若是啓用了安全管理器,默認會使用jre自帶的安全策略文件$JAVA_HOME/jre/lib/security/java.policy來指定訪問外部資源的權限,該策略文件也能夠經過jvm參數-Djava.security.policy來指定。ide

Policy文件的主要格式以下:測試

keystore "some_keystore_url", "keystore_type";
grant [SignedBy "signer_names"] [, CodeBase "URL"] {
    Permission permission_class_name ["target_name"] [,"action"] [,SignedBy"signer_names"];
    … …
};

  1. "keystore"記錄 ui

    一個keystore是一個私有密鑰(private keys)數據庫和相應的數字簽名,例如X.509證書。Policy文件中可能只有一條keystore記錄(也可能不含有該記錄),它能夠出如今文件中grant記錄之外的任何地方。Policy配置文件中指定的keystores用於尋找grant記錄中指定的、簽名者的公共密鑰(public keys),若是任何grant記錄指定簽名者(signer_names),那麼,keystore記錄必須出如今policy配置文件中。

    "some_keystore_url"是指keystore的URL位置,"keystore_type"是指keystore的類型。第二個選項是可選項,若是沒有指定,該類型則假定由安全屬性文件(java.security)中的"keystore.type"屬性來肯定。keystore類型定義了keystore信息的存儲和數據格式,用於保護keystore中的私有密鑰和keystore完整性的算法。Sun Microsystems支持的缺省類型爲「JKS」。

  2. "grant"記錄

    Policy文件中的每個grant記錄含有一個CodeSource(指定代碼)及其permission(許可)Policy文件中的每一條grant記錄遵循下面的格式,以保留字「grant」開頭,表示一條新的記錄的開始,「Permission」是另外一個保留字,在記錄中用來標記一個新的許可的開始。每個grant記錄授予一個指定的代碼(CodeBase)一套許可(Permissions)。permission_class_name必須是一個合格並存在的全限定性類名,例如java.io.FilePermission

    target_name用來指定目標類的位置,action用於指定目標類擁有的權限。 target_name能夠直接指定類名(能夠是絕對或相對路徑),目錄名,也可使用通配符/、/*或着/-。

    directory/ 表示directory目錄下的全部.class文件,不包括.jar文件

    directory/* 表示directory目錄下的全部的.class及.jar文件

    directory/- 表示directory目錄下的全部的.class及.jar文件,包括子目錄

下面是一個policy文件的demo:

grant codeBase "file:${{java.ext.dirs}}/*" {
        permission java.security.AllPermission;
};
grant {
        permission java.lang.RuntimePermission "stopThread";
        permission java.net.SocketPermission "localhost:1099", "listen";        
        permission java.util.PropertyPermission "java.version", "read";
        ... ...
};

例如:對於java.net.SocketPermissionaction能夠是:listenacceptconnectreadwrite;對於java.io.FilePermission,action能夠是:read, write, delete和execute。

安全管理器

java的安全管理器能夠定製,也可使用jdk的默認實現java.lang.SecurityManager,啓動安全管理器的話有兩種方式,一種是經過硬編碼的方式啓動,另一種是經過jvm參數-Djava.security.manager啓動。

下面的測試用例都使用jre的默認policy文件配置:

grant {
        ... ...       
        permission java.util.PropertyPermission "java.version", "read";
        ... ...
};

該策略文件指定了"java.version"的讀權限,而後並無指定寫權限。參考如下測試用例:

public static void main(String... args) {
    String javaVersion=System.getProperty("java.version");
    System.err.println(javaVersion);
    System.setProperty("java.version","1.7.0_45");
    String javaNewVersion=System.getProperty("java.version");
    System.err.println(javaNewVersion);
  }

首先讀"java.version"屬性,而後把該屬性改寫爲1.7.0_45,最後再讀取它並打印出來,輸出結果爲:

1.8.0_45
1.7.0_45

能夠看到默認的jdk版本爲1.8.0_45(1.8.0是java的主版本號,45是次版本號)。

而後前面的policy文件只指定了read權限,爲何這裏卻write成功了?那是由於默認狀況下java並不啓動安全管理器,可使用硬編碼System.setSecurityManager()來啓動安全管理器,參考如下測試用例:

public static void main(String... args) {
    // 啓用安全管理器
    System.setSecurityManager(new SecurityManager());
    String javaVersion=System.getProperty("java.version");
    System.err.println(javaVersion);
    System.setProperty("java.version","1.7.0_45");
    String javaNewVersion=System.getProperty("java.version");
    System.err.println(javaNewVersion);
  }

此時的輸出結果爲:

1.8.0_45
Exception in thread "main" java.security.AccessControlException: access denied ("java.util.PropertyPermission" "java.version" "write")
	at java.security.AccessControlContext.checkPermission(AccessControlContext.java:457)
	at java.security.AccessController.checkPermission(AccessController.java:884)
	at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
	at java.lang.System.setProperty(System.java:792)
	at test.Test.main(Test.java:9)

結果很明確:能夠讀,但不能寫,咱們能夠來修改policy文件,讓它支持"java.version"的寫操做:

grant {
        ... ...       
        permission java.util.PropertyPermission "java.version", "read";
        permission java.util.PropertyPermission "java.version", "write";
        ... ...
};

此時再執行上面的用例,輸出結果爲:

1.8.0_45
1.7.0_45

能夠看到此時能夠支持"java.version"的寫操做了。

另外使用jvm參數-Djava.security.manager也能啓用安全管理器,此時jvm啓動時會設置"java.security.manager"系統屬性爲空字符串"",此時會在啓動sun.misc.Launcher時初始化安全管理器,查看sun.misc.Launcher的源碼:

public Launcher(){
        ExtClassLoader extclassloader;
        try {
            extclassloader = ExtClassLoader.getExtClassLoader();
        } catch(IOException ioexception) {
            throw new InternalError("Could not create extension class loader", ioexception);
        }
        try {
            loader = AppClassLoader.getAppClassLoader(extclassloader);
        } catch(IOException ioexception1) {
            throw new InternalError("Could not create application class loader", ioexception1);
        }
        Thread.currentThread().setContextClassLoader(loader);
        String s = System.getProperty("java.security.manager");
        if(s != null) {
            SecurityManager securitymanager = null;
            if("".equals(s) || "default".equals(s))
                securitymanager = new SecurityManager();
            else
                try {
                    securitymanager = (SecurityManager)loader.loadClass(s).newInstance();
                }
                catch(IllegalAccessException illegalaccessexception) { }
                catch(InstantiationException instantiationexception) { }
                catch(ClassNotFoundException classnotfoundexception) { }
                catch(ClassCastException classcastexception) { }
            if(securitymanager != null)
                System.setSecurityManager(securitymanager);
            else
                throw new InternalError((new StringBuilder()).append("Could not create SecurityManager: ").append(s).toString());
        }
    }

能夠看到"java.security.manager"系統屬性爲空字符串""時會啓用jdk的默認安全管理器SecurityManager。

Java API

java的安全機制api大部分都在java.security包下,由於源碼不少,就不貼出來了,你們感興趣的話能夠研究下。如下是一些經常使用的類的api介紹:

  • java.security.AccessControlContext:基於它所封裝的上下文做出系統資源訪問決定,該類最經常使用於將代碼標記爲享有「特權」。

  • java.security.AccessController:用於與訪問控制相關的操做和決定。java.security.SecureClassLoader此類擴展了 ClassLoader,支持使用相關的代碼源和權限定義類,這些代碼源和權限默認狀況下可根據系統策略獲取到。

  • java.security.Provider:此類表示 Java 安全 API "provider",這裏 provider 實現了 Java 安全性的一部分或者所有。

  • java.security.Permission:表示訪問系統資源的抽象類。全部權限都有一個名稱(對它們的解釋依賴於子類),以及用來定義特定 Permission 子類的語義的抽象方法。

相關文章
相關標籤/搜索