亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

實例分析JVM安全體系:雙親委派、命名空間、保護域、策略

2019-11-14 15:25:02
字體:
來源:轉載
供稿:網友

在了解雙親委派模型之前,先了解一下類加載器的概念: 

類加載器的作用就是將真實的class文件根據位置將該java類的字節碼裝入內存,并生成對應的Class對象。用戶可以通過繼承ClassLoader和重寫findClass方法來定義自己的類加載器進行加載,系統類加載器按照層次,分為: 
(1).啟動類加載器(Bootstrap ClassLoader):將加載 /JAVAHOME/lib以及為-Xbootclasspath所指定的目錄下的類庫,是核心Java API的class文件,用于啟動Java虛擬機 
(2).擴展類加載器(Extension ClassLoader):將加載/JAVAHOME/lib/ext以及為java.ext.dirs所指定的目錄下的類庫 
(3).應用程序類加載器(application/System ClassLoader):將加載ClassPath下所指定的類庫,或者稱為類路徑加載器

 1.雙親委派 


  類的加載將使用雙親委派的方式,注意這里的雙親關系并非通過繼承來實現,而是加載器之間指定或默認的委托加載關系,可以看到在/java/lang/ClassLoader.java中,通過ClassLoader的構造方法顯式指定了其父加載器,而若沒有指定父加載器,那么將會把系統類加載器AppClassLoader作為默認的父加載器

PRivate ClassLoader(Void unused, ClassLoader parent) {        this.parent = parent;        //...}protected ClassLoader() {        //getSystemClassLoader()        this(checkCreateClassLoader(), getSystemClassLoader());}

  加載器對類的加載調用loadClass()方法實現:

 1 protected Class<?> loadClass(String name, boolean resolve) 2         throws ClassNotFoundException 3     { 4         synchronized (getClassLoadingLock(name)) { 5             // First, check if the class has already been loaded 6             Class c = findLoadedClass(name); 7             // 該類沒有被加載 8             if (c == null) {  9                 long t0 = System.nanoTime();10                 try {11                     if (parent != null) {12                     // 先交由父加載器嘗試加載13                         c = parent.loadClass(name, false);14                     } else {15                     // 父加載器為空,即為BootstrapClassLoader,那么查看啟動類中是否有該類16                         c = findBootstrapClassOrNull(name);17                     }18                 } catch (ClassNotFoundException e) {19                     // ClassNotFoundException thrown if class not found20                     // from the non-null parent class loader21                 }22                 //父類無法加載該類,則由自己嘗試加載23                 if (c == null) {24                     // If still not found, then invoke findClass in order25                     // to find the class.26                     long t1 = System.nanoTime();27                     c = findClass(name);28 29                     // this is the defining class loader; record the stats30                     sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);31                     sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);32                     sun.misc.PerfCounter.getFindClasses().increment();33                 }34             }35             if (resolve) {36                 resolveClass(c);37             }38             return c;39         }40     }

  可見首先會檢查該類是否已經被加載,若沒有被加載,則會委托父加載器進行裝載,只有當父加載器無法加載時,才會調用自身的findClass()方法進行加載。這樣避免了子加載器加載一些試圖冒名頂替可信任類的不可靠類,也不會讓子加載器去實現父加載器實現的加載工作。 
  比如某個用戶自定義的類加載器試圖加載一個叫做“java.lang.String”的類,那么,該類會最終委派給啟動類加載器BootstrapClassLoader嘗試加載,那么啟動類加載器將加載Java API中的”java.lang.String”類而不會通過用戶自定義的類加載器去獲得和加載這個看上去不懷好意的冒名類。

  但是僅僅依賴雙親委派是遠遠不夠的,假設這個用戶自定義的類加載器試圖加載一個叫做“java.lang.Bomb”的危險類,而父類加載器無法加載該類,那么加載工作將由用戶定義的加載器負責實現。由于一個類的同一包內的類(和其子類)可以訪問其protected成員,這個“java.lang.Bomb”則可能訪問可信任類的一些敏感信息,所以就必須將這個類與可信任類的訪問域隔離,Java虛擬機只把這樣彼此訪問的特殊權限授予由同一個類加載器加載的同一包內的類型,這樣一個由同一個類加載器加載的、屬于同一個包的多個類型集合稱為運行時包。

2.命名空間 


  類加載體系為不同類加載器加載的類提供不同的命名空間,同一命名空間內的類可以互相訪問,不同命名空間的類不知道彼此的存在(除非顯式提供訪問機制)。同一類可以再不同的命名空間內,但無法在同一命名空間內重復出現。

命名空間是這樣定義的:實際完成加載類的工作的加載器為定義類加載器,而加載的雙親委托路徑上的所有加載器為初始類加載器,某個加載器的命名空間就是所有以該加載器為初始類加載器的類所組成。

可以預見,子加載器的命名空間包括其父/祖先加載器的命名空間和只有自己才可以加載的類所組成。根據加載體系結構的安全機制,同一命名空間內的類可以互相訪問,所以父加載器所加載的類不一定可以訪問子加載器所加載的類,但子加載器所加載的類必然可以訪問父加載器加載的類。父加載器加載的類就好像小箱子,子加載器加載的類可能用到父加載器加載的類,就像一個大箱子,只能把小箱子放進大箱子,而不能反過來做(當然顯式的訪問機制除外)

以自己實現的類加載器為例:

  1 package com.ice.classloader;  2   3   4 import java.io.ByteArrayOutputStream;  5 import java.io.File;  6 import java.io.FileInputStream;  7 import java.io.FileNotFoundException;  8 import java.io.IOException;  9 import java.io.InputStream; 10  11 public class MyClassLoader extends ClassLoader { 12  13     private String name;    //加載器名稱 14     private String path = "E://WorkSpace//ClassLoaderTest//";  //加載路徑 15     private static final String HOME = "E://WorkSpace//ClassLoaderTest//"; 16     private final String classFileType = ".class";  17  18     public MyClassLoader(String name) { 19         super();  20         this.name = name; 21     } 22  23     public MyClassLoader(ClassLoader parent, String name) { 24         super(parent);  25         this.name = name; 26     } 27  28     @Override 29     public String toString() { 30         return this.name; 31     } 32  33     public String getPath() { 34         return path; 35     } 36  37     public void setPath(String path) { 38         this.path = path; 39     } 40  41     @Override 42     public Class<?> findClass(String name) throws ClassNotFoundException { 43         byte[] data = this.loadClassData(name); 44         if(data == null) 45             throw new ClassNotFoundException(); 46         return this.defineClass(name, data, 0, data.length); 47  48     } 49  50     private byte[] loadClassData(String name) { 51  52         InputStream is = null; 53         byte[] data = null; 54         ByteArrayOutputStream baos = null; 55 //        System.out.println("  classloader:" + this.name + " try to load"); 56         try { 57             //類名轉化為路徑 58             name = name.replace(".", "http://"); 59             is = new FileInputStream(new File(path + name + classFileType)); 60  61             baos = new ByteArrayOutputStream(); 62             int ch = 0; 63             while (-1 != (ch = is.read())) { 64  65                 baos.write(ch); 66             } 67  68             data = baos.toByteArray(); 69         } 70         catch (FileNotFoundException e) { 71 //            e.printStackTrace(); 72             return null; 73         } 74         catch (IOException ioe) { 75             ioe.printStackTrace(); 76       } 77         finally { 78             try { 79                 is.close(); 80                 baos.close(); 81             } 82             catch (Exception e2) { 83             } 84         } 85         return data; 86     } 87  88  89     public static void main(String[] args) throws Exception { 90         //假定的系統加載器 91         MyClassLoader father = new MyClassLoader("father"); 92         father.setPath(HOME + "syslib//"); 93  94         MyClassLoader child = new MyClassLoader(father, "child"); 95         child.setPath(HOME + "ext//"); 96  97         MyClassLoader user = new MyClassLoader("user"); 98         user.setPath(HOME + "usr//"); 99         System.out.println("-------------test parent--------------");100         //測試父加載器關系101         traverseParent(child);102         System.out.println("-------------test load begin from child--------------");103         //測試加載104         test(child);105         //測試命名空間106         System.out.println("-------------test namespace--------------");107         testNameSpace(user);108 109     }110 111     public static void traverseParent(ClassLoader loader) throws Exception{112         if(loader == null) return;113         System.out.println("travase classloader:" + loader.toString());114         while(loader.getParent() != null){115             System.out.println(loader.getParent());116             loader = loader.getParent();117         }118     }119 120     public static void test(ClassLoader loader) throws Exception {121         Class<?> clazz = loader.loadClass("com.ice.classloader.LoadedClass");122         Object object = clazz.newInstance();123     }124 125     public static void testNameSpace(ClassLoader loader) throws Exception {126         Class<?> clazz = loader.loadClass("com.ice.classloader.LoadedClass");127         Object object = clazz.newInstance();128         try{129             LoadedClass lc = (LoadedClass) object;130         }catch(Exception e){131             e.printStackTrace();132         }133     }134 }

  被加載類LoadedClass的定義如下:

 1 //被加載類 2 package com.ice.classloader; 3  4 public class LoadedClass { 5  6     public LoadedClass() { 7         System.out.println("LoadedClass is loaded by: " 8                 + this.getClass().getClassLoader()); 9 10     }11 12 }

(1).雙親委派結果 
  child加載器會委托father進行加載,若father的加載目錄下存在著對應的class文件,則會由父加載器father進行對應的加載工作(father也會交由AppClassLoader和ExtClassLoader嘗試進行加載,但這兩個加載器并不知道如何加載,故而最后會自己嘗試進行加載) 

  當father的加載目錄下沒有對應的class文件,則會交由child進行加載 

(2).命名空間隔離 
  由于MyClassLoader是通過系統的(應用程序類加載器/類路徑加載器加載的),而LoadedClass是由user加載器所加載的,AppClassLoader加載器是user加載器的父加載器,故由父加載器加載的類MyClassLoader無法看見子加載器user所加載的LoadedClass類,在MyClassLoader中嘗試實例化LoadedClass類時就會出現如下錯誤:

  對應出錯的正是嘗試實例化LoadedClass類的那一行 

128         try{129             LoadedClass lc = (LoadedClass) object;130         }catch(Exception e){

(3).運行時包 
  當請求加載一個com.ice.classloader.virus類時,AppClassLoader路徑下沒有該類的class文件,那么attaker加載器將會加載這個virus類,并暗示其為com.ice.classloader的一部分,該類想要獲取com.ice.classloader包下被信任類的訪問權限。但由于權限檢查時,由于該Virus類由attacker加載而非AppClassLoader加載,故對MyClassLoader受保護成員的訪問將會被阻止。

 1 package com.ice.classloader; 2  3 public class Virus { 4  5     public Virus() { 6         System.out.println("Virus is loaded by: " 7                 + this.getClass().getClassLoader()); 8         MyClassLoader cl = (MyClassLoader) this.getClass().getClassLoader(); 9         System.out.println("secret is:" + cl.secret);10     }11 12 }

  MyClassLoader 由AppClassLoader所加載,而Virus由用戶自定義的加載器attacker所加載,雖然AppClassLoader是attacker的父加載器,即MyClassLoader對Virus可見,但由于兩者不是由同一個加載器所加載,即不屬于同一個運行時包,那么Virus對MyClassLoader的受保護成員訪問受限

 1 public class MyClassLoader extends ClassLoader { 2     protected int secret = -1; 3 //... 4     public static void main(String[] args) throws Exception { 5             //其父加載器為Bootstrap ClassLoader 6             MyClassLoader loader = new MyClassLoader(null, "loader"); 7             loader.setPath(HOME + "usr//"); 8  9             MyClassLoader attacker = new MyClassLoader("attacker");10             attacker.setPath(HOME + "attacker//");11 12             System.out.println("MyClassLoader's classloader:" + MyClassLoader.class.getClassLoader());13 14             System.out.println("-------------test parent--------------");15             //測試父加載器關系16             traverseParent(attacker);17 18             System.out.println("-------------test in-package access--------------");19             testVirus(attacker);20 21         }22 23         public static void traverseParent(ClassLoader loader) throws Exception{24             if(loader == null) return;25             System.out.println("travase classloader:" + loader.toString());26             while(loader.getParent() != null){27                 System.out.println(loader.getParent());28                 loader = loader.getParent();29             }30         }31 32 33         public static void testVirus(ClassLoader loader) throws Exception {34             Class<?> clazz = loader.loadClass("com.ice.classloader.Virus");35             Object object = clazz.newInstance();36         }37     }

結果如下: 

  注意命名空間的隔離與運行時包隔離的區別,不同命名空間的類之間不可見,而同一命名空間內的類可能由不同的加載器進行加載,如啟動類加載器加載的核心JavaAPI和用戶自定義加載器加載的類,這些類及時聲明定義為同一個包,但是由于不是由同一個加載器加載的,即不屬于同一個運行時包,那么不同運行時包內的類之間就存在對包可見成員的訪問限制。

3.策略與保護域 
  除了命名空間的訪問隔離和雙親委派的受信類保護,類加載器體系還是用保護域來定義代碼在運行時可以獲得的權限。同樣在分析保護域之前,先了解類Java虛擬機的安全訪問控制及策略。

  Java的沙箱模型可以由用戶自定義,這是通過用戶定制沙箱的安全管理器(SecurityManager)來定義沙箱的安全邊界,以為程序運行指定用戶自定義的安全策略和訪問控制。應用程序通過System.setSecurityManager()/“-Djava.security.manager”來指定/啟動安全管理器,每當JavaAPI執行一些可能不安全的操作時,如對文件的讀寫和刪除等,就會向安全管理器進行權限檢查,若權限檢查不通過,將會拋出一個安全異常,若權限檢查通過,則允許該操作的執行。

  比如創建一個FileInputStream時,會調用SecurityManager的checkRead()進行讀取權限的檢查:

 1 public FileInputStream(File file) throws FileNotFoundException { 2         String name = (file != null ? file.getPath() : null); 3         SecurityManager security = System.getSecurityManager(); 4         if (security != null) { 5             security.checkRead(name); 6         } 7         if (name == null) { 8             throw new NullPointerException(); 9         }10         fd = new FileDescriptor();11         fd.incrementAndGetUseCount();12         open(name);13     }

  checkRead()即以讀動作的FilePermission為參數調用checkPermission()

1 public void checkRead(String file) {2         checkPermission(new FilePermission(file,3             SecurityConstants.FILE_READ_ACTION));4     }

  jdk1.2版本后,可以使用checkPermission(Permission perm)和checkPermission(Permission perm, Object context)來進行權限檢查,其中perm為請求執行操作所需要的權限,如java.io.FilePermission對“/usr/indata.txt”請求“read”操作。checkPermission()實際上在對當前線程的方法棧進行優化后,獲得一個訪問控制環境AccessControlContext,并調用其checkPermission()方法

 1 public static void checkPermission(Permission perm) 2                  throws AccessControlException 3     { 4         //System.err.println("checkPermission "+perm); 5         //Thread.currentThread().dumpStack(); 6  7         if (perm == null) { 8             throw new NullPointerException("permission can't be null"); 9         }10 11         AccessControlContext stack = getStackAccessControlContext();12         // if context is null, we had privileged system code on the stack.13         if (stack == null) {14            //...debug相關15             return;16         }17 18         AccessControlContext acc = stack.optimize();19         acc.checkPermission(perm);20     }

  checkPermission()會從方法的棧頂向棧底遍歷(檢查方法所在類的保護域權限,context是一個ProtectionDomain數組),當遇到一個沒有權限的棧幀就會拋出一個AccessControlException。即對于一次需要進行權限檢查的訪問,對于該訪問的方法的每一個調用層次都必須具有對應的訪問權限。 
  對權限的判定是通過implies()來進行的,implies()在Permission類、PermissionCollection、ProtectionDomain類中聲明。在Permission類(具體實現的子類)中,該方法將確定由該Permission所代表的對象,是否隱含了將要判斷的Permission對象的權限中,如對”/test/*”目錄的讀寫權限testAllPermission,隱含了對”/test/test.txt”文件的讀寫權限testFilePermission,即testAllPermission.implies(testFilePermission) 的值為true,反之為false。 在ProtectionDomain(其PermissionCollection)中,將進行權限集合內implies()的判定,實際上就是在PermissionCollection中遍歷保護域所擁有的權限,調用implies()判定其是否具有對應的訪問權限。

 1 public void checkPermission(Permission perm) 2         throws AccessControlException 3     { 4        //... 5         if (context == null) 6             return; 7  8         for (int i=0; i< context.length; i++) { 9             if (context[i] != null &&  !context[i].implies(perm)) {10                 //...11                 throw new AccessControlException("access denied "+perm, perm);12             }13         }14 15         // ...16 17         return;18     }

那么,類的訪問權限(保護域)是如何指定的? 
(1).類與訪問權限是什么? 
每個class文件均和一個代碼來源相關聯,這個代碼來源(java.security.CodeSource)通過URL類成員location指向代碼庫和對該class文件進行簽名的零個或多個證書對象的數組(class文件在進行代碼認證的過程中可能經過多個證書簽名,也可能沒有進行簽名) 。 
訪問控制策略Policy對權限的授予是以CodeSource為基礎進行的,每個CodeSource擁有若干個Permission,這些Permission對象會被具體地以其子類,如FilePermission、SocketPermission等描述,并且和CodeSource相關聯的Permission對象將被封裝在java.security.PermissionCollection(抽象類)的一個子類實例中,以描述該CodeSource所獲取的權限。 
(2).從類的加載到保護域探尋類訪問權限的指定:
加載器會調用defineClass解析和加載類的Class實例:

 1 protected final Class<?> defineClass(String name, byte[] b, int off, int len, 2                                          ProtectionDomain protectionDomain) 3         throws ClassFormatError 4     { 5         protectionDomain = preDefineClass(name, protectionDomain); 6  7         Class c = null; 8         String source = defineClassSourceLocation(protectionDomain); 9 10         try {11             c = defineClass1(name, b, off, len, protectionDomain, source);12         } catch (ClassFormatError cfe) {13             c = defineTransformedClass(name, b, off, len, protectionDomain, cfe,14                                        source);15         }16 17         postDefineClass(c, protectionDomain);18         return c;19     }

在defineClass()中,會調用preDefineClass()獲取ProtectionDomain:

 1 private ProtectionDomain preDefineClass(String name, 2                                             ProtectionDomain pd) 3     { 4         if (!checkName(name)) 5             throw new NoClassDefFoundError("IllegalName: " + name); 6  7         if ((name != null) && name.startsWith("java.")) { 8             throw new SecurityException 9                 ("Prohibited package name: " +10                  name.substring(0, name.lastIndexOf('.')));11         }12         if (pd == null) {13             pd = defaultDomain;14         }15 16         if (name != null) checkCerts(name, pd.getCodeSource());17 18         return pd;19     }

當沒有指定保護域時,就會為其指定一個空的保護域,若指定了保護域則使用加載器所指定的保護域。

類加載器的實現可以通過將代碼來源(CodeSource),即代碼庫和該class文件的所有簽名者信息,傳遞給當前的Policy對象的getPermissions()方法,來查詢該代碼來源所擁有的權限集合PermissionCollection(在策略初始化時生成),并以此構造一個保護域傳遞給defineClass(),以此指定類的保護域。

 (3).Java應用程序訪問控制策略是由抽象類java.security.Policy的子類實例所描述的,通過設置policy.provider屬性值來指定Policy的實現類,該屬性值定義在/jre/lib/security/java.security文件中

## Class to instantiate as the system Policy. This is the name of the class# that will be used as the Policy object.#policy.provider=sun.security.provider.PolicyFile

可見默認是使用PolicyFile類來實現訪問控制策略,該類將使用從策略文件中讀取并解析訪問控制策略的方式形成策略。 
也可以通過實現自己的Policy并調用Policy的setPolicy()方法來替換當前Policy對象。

對Java應用程序的訪問控制策略是由抽象類java.security.Policy的子類實例實現的,其實現方式可以采用很多種方法,如從一個結構化ASCII文件中讀取,從一個Policy的二進制class文件中讀取,從一個數據庫中讀取,PolicyFile就是使用了從ASCII策略文件中讀取的方法,策略文件定義在/jre/lib/security/java.security中:

1 # The default is to have a single system-wide policy file,2 # and a policy file in the user's home directory.3 policy.url.1=file:${java.home}/lib/security/java.policy4 policy.url.2=file:${user.home}/.java.policy

可以在java.security文件中修改或添加policy.url.x來指定用戶自己想要的策略,也可以在運行時使用”-Djava.security.policy”命令行參數進行設置,如: 
-Djava.security.manager -Djava.security.policy = mypolicy.txt 
其中如果沒有指定java.security.manager,那么應用程序就不會安裝任何的安全管理器,而代碼也就沒有任何權限限制。mypolicy.txt就是用戶自頂一個策略文件,這里使用的是相對路徑,將使用程序的啟動目錄

以/jre/lib/security/java.policy為例說明策略文件,在該文件中使用上下文無關文法描述安全策略 
如:

grant codeBase "file:${{java.ext.dirs}}/*" {    permission java.security.AllPermission;};

policy文件的基本語法如下:

keystore "keystore_url","keystore_type";grant [SignedBy "signer_names"] [, CodeBase "URL"] [,principal principal_class_name "principal_name",]{Permission permission_class_name[ "target_name" ][, "action"] [, SignedBy "signer_names"];Permission ...};
  • keystore: 
    keystore_url指定了簽名者的公鑰的證書文件所在位置,可以使相對URL,如keystore “mykey”,這個相對路徑指向了程序使用該策略文件的啟動目錄,比如,該策略文件由policy.url.x指定在”e://security/policy/mypolicy.txt”,那么公鑰證書就在”e://security/policy/mykey”文件中。當然也可以使用絕對路徑指定公鑰路徑。 
    keystore_type指定了密鑰倉庫信息的存儲和數據格式,也定義了保護密鑰倉庫中私鑰和密鑰倉庫完整性的算法,默認將使”JKS”類型
  • grant子句: 
    授予 指定類型(代碼) 指定權限 
    其中對代碼類型的描述有兩種: 
    signedBy表示簽名者別名,可以是由”,”分隔的若干個簽名者 
    codeBase表示一個特定的加載位置,從該目錄下加載的代碼都將被賦予特定的權限
  • permission: 
    permission由權限類型、操作目標、操作動作三部分組成,如 
    permission java.io.FilePermission “note.txt” “read”即為對程序啟動目錄下(相對路徑)的note.txt的讀取權限

最后以深入jvm(第二版)一書中的例子來介紹策略文件的使用以及保護域的作用:

Doer接口:

1 // /com/ice/security/doer/Doer.java2 package com.ice.security.doer;3 4 public interface Doer {5     void doYourThing();6 }

Doer的實現類Friend,由Friend所簽名,將作為受信認類訪問“friend.txt”和“stranger.txt”

 1 // /com/ice/security/friend/Friend.java 2 package com.ice.security.friend; 3  4 import java.security.AccessController; 5 import java.security.PrivilegedAction; 6  7 import com.ice.security.doer.Doer; 8  9 public class Friend implements Doer{10     private Doer next;11     private boolean direct;12 13     public Friend(Doer next, boolean direct){14         this.next = next;15         this.direct = direct;16     }17 18     @Override19     public void doYourThing() {20         if(direct){21             next.doYourThing();22         }else{23             AccessController.doPrivileged(24                     new PrivilegedAction() {25                         public Object run(){26                             next.doYourThing();27                             return null;28                         }29                     }30             );31         }32     }33 34 }

Doer的實現類Stranger,由Stranger所簽名,作為不受信認類,僅能訪問“stranger.txt”

//com/ice/security/stranger/Stranger.javapackage com.ice.security.stranger;import java.security.AccessController;import java.security.PrivilegedAction;import com.ice.security.doer.Doer;public class Stranger implements Doer{    private Doer next;    private boolean direct;    public Stranger(Doer next, boolean direct){        this.next = next;        this.direct = direct;    }    @Override    public void doYourThing() {        if(direct){            next.doYourThing();        }else{            AccessController.doPrivileged(                    new PrivilegedAction() {                        public Object run(){                            next.doYourThing();                            return null;                        }                    }            );        }    }}

txt文件的顯示輸出類TextFileDisplayer:

 1 //TextFileDisplayer.java 2 import java.io.CharArrayWriter; 3 import java.io.FileReader; 4 import java.io.IOException; 5  6 import com.ice.security.doer.Doer; 7  8  9 public class TextFileDisplayer implements Doer{10     private String fileName;11     public TextFileDisplayer(String fileName){12         this.fileName = fileName;13     }14 15     @Override16     public void doYourThing() {17             try{18                 FileReader fr = new FileReader(fileName);19                 try {20                     CharArrayWriter caw = new CharArrayWriter();21                     int c;22                     while((c = fr.read()) != -1){23                         caw.write(c);24                     }25                     System.out.println(caw.toString());26                 } catch (IOException e) {27 28                 }finally{29                     try{30                         fr.close();31                     }catch (IOException e){32 33                     }34                 }35             }catch (IOException e) {36 37             }38     }39 40 }

1.將Friend和Stranger分別導出為jar文件,放在指定目錄(這里放在”E:/java/security”目錄下)以待不同的機構進行簽名,Friend所在包假定為比較有信用的機構”friend”進行簽名,而Stranger所在包假定為一個不受信任的機構”stranger”進行簽名。 
(1).調用命令 jar cvf xxx.jar <_ClassPath> 進行打包 
(注意打包后,若沒有把jar包放在單獨的目錄下,需要刪除原java文件編譯產生的class文件,以免程序運行直接加載目錄下class文件而非包內的class文件) 
這里分別調用 
jar cvf friend.jar com/ice/security/friend/*.class 將friend包內的class文件打包 

jar cvf stranger.jar com/ice/security/stranger/*.class 將friend包內的class文件打包 

(2).使用keytool可以用來生成新的密鑰對,并與一個別名關聯,用密碼加以保護存放在keystore文件中 
使用keytool -genkey -alias friend -keypass 123456 -validity 10000 -keystore mykey 命令: 

該密鑰的別名是friend,別名密碼是123456(至少6位),有效期是10000天,存放在一個mykey的keystore文件中,keystore密碼為myfriendkey 

類似地,生成一個別名stranger的密鑰對

為了方便起見,兩個不同的簽名者stranger和friend的密鑰均存放在mykey中,mykey的訪問密碼是myfriendkey,密鑰的訪問密碼都是123456 

可以看到在目錄下生成了一個mykey文件 
(3).使用jarsigner -keystore -storepass -keypass 命令進行簽名 
這里: 
jarsigner -keystore mykey -storepass myfriendkey -keypass 123456 friend.jar friend 
jarsigner -keystore mykey -storepass myfriendkey -keypass 123456 stranger.jar stranger 
使用friend密鑰對friend.jar進行簽名,使用stranger密鑰對stranger.jar進行簽名 

(4).最后可以使用 
keytool -export -alias -storepass -file -keystore 
這里分別用: 
keytool -export -alias friend -storepass myfriendkey -file friend.cer -keystore mykey 
keytool -export -alias stranger -storepass myfriendkey -file stranger.cer -keystore mykey 
導出friend和stranger的發行證書 

 

2.編寫自己的策略文件,放在當前目錄下

//mypolicy.txtkeystore "mykey";grant signedBy "friend"{    permission java.io.FilePermission "friend.txt","read";    permission java.io.FilePermission "stranger.txt","read";};grant signedBy "stranger"{    permission java.io.FilePermission "stranger.txt","read";};grant codeBase "file:${com.ice.home}/com*"{    permission java.io.FilePermission "friend.txt","read";    permission java.io.FilePermission "stranger.txt","read";};

這里friend簽名的類和${com.ice.home}.com(后面設置為”e:/java/security/com”,存放著Doer接口的class文件)可以讀取”friend.txt”和”stranger.txt”,而stranger簽名的類只能讀取”stranger.txt” 
(這里為了方便,直接使用mykey而非發布的證書) 
(1).添加Doer接口類的class文件(對應路徑)和friend.txt和stranger.txt兩個測試文件 
(2).通過權限檢查的例子:

1 public class ProtectionDomainTest {2     public static void main(String[] args){3     TextFileDisplayer tfd = new TextFileDisplayer("stranger.txt");4     Friend friend = new Friend(tfd, true);5     Stranger stranger = new Stranger(friend, true);6     stranger.doYourThing();7     }8 }

調用java -Djava.security.manager -Djava.security.policy=mypolicy.txt -Dcom.ice.home=e:/java/security -cp .;friend.jar;stranger.jar ProtectionDomainTest測試運行,其中指定了com.ice.home的路徑,通過-cp設置了類路徑 

(3).不能通過權限檢查的例子:

1 public class ProtectionDomainTest {2     public static void main(String[] args){3     TextFileDisplayer tfd = new TextFileDisplayer("friend.txt");4     Friend friend = new Friend(tfd, true);5     Stranger stranger = new Stranger(friend, true);6     stranger.doYourThing();7     }8 }

與(2)類似,但stranger會嘗試讓friend讀取”friend.txt”,這會被阻止 


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲最新av网址| 国产精品91视频| 成人国产精品一区| 久久久久久久999精品视频| 中文字幕欧美精品日韩中文字幕| 亚洲人永久免费| 国产精品无码专区在线观看| 成人av在线网址| 韩国一区二区电影| 国产精品偷伦视频免费观看国产| 亚洲日韩中文字幕| 欧美日韩aaaa| 4438全国成人免费| 一个人www欧美| 国产欧美一区二区三区视频| 国产美女扒开尿口久久久| 人人澡人人澡人人看欧美| 久久精品国产一区二区三区| 国产一区二区成人| 富二代精品短视频| 久久夜精品va视频免费观看| 国产精品久久久久久久久久久新郎| 亚洲品质视频自拍网| 91高潮精品免费porn| 精品久久久久久国产| 久热精品在线视频| 亚洲视频国产视频| 久久综合久中文字幕青草| 韩国视频理论视频久久| 91九色视频导航| 久久精品国产96久久久香蕉| 精品欧美aⅴ在线网站| 色中色综合影院手机版在线观看| 久久不射电影网| 亚洲精品短视频| 久久久精品一区| 日韩av资源在线播放| 亚洲国产成人精品女人久久久| 色综合天天狠天天透天天伊人| 97视频在线观看播放| 亚洲电影在线看| 91精品国产乱码久久久久久蜜臀| 国产精品高潮呻吟久久av野狼| 亚洲成人精品视频在线观看| 国产精品视频免费在线观看| 日本三级久久久| 国产精品日韩欧美大师| 欧美一级淫片丝袜脚交| 久久香蕉国产线看观看网| 97视频免费在线看| 久久夜色精品国产亚洲aⅴ| 97久久久久久| 欧美大学生性色视频| 国产日韩欧美91| 欧美中文字幕精品| 日本精品在线视频| 国产精品视频免费观看www| 欧美激情欧美激情| 亚洲二区在线播放视频| 久久青草精品视频免费观看| 欧美特黄级在线| 少妇高潮久久久久久潘金莲| 2018中文字幕一区二区三区| 欧美在线中文字幕| 全球成人中文在线| 91视频88av| 5566日本婷婷色中文字幕97| 欧美日韩一二三四五区| 中文字幕国产日韩| 亚洲一区二区三区久久| 自拍偷拍亚洲一区| 久久久亚洲福利精品午夜| 亚洲国产精品高清久久久| 4p变态网欧美系列| 国产日产欧美a一级在线| 福利微拍一区二区| 久久精品国产一区二区三区| 88国产精品欧美一区二区三区| 91av视频在线| 欧美成人激情在线| 国产成人啪精品视频免费网| 欧美精品aaa| 国产日韩精品一区二区| 91香蕉嫩草影院入口| 国产精品一区二区性色av| 伦理中文字幕亚洲| 亚洲自拍小视频| 亚洲第一av网| 国产精品户外野外| 精品高清美女精品国产区| 国产精品激情av在线播放| 国产亚洲精品日韩| 久久在线免费视频| 日本精品久久久久久久| 精品呦交小u女在线| 亚洲精品在线不卡| 亚洲美女动态图120秒| 国产日韩精品入口| 国产一区二区三区三区在线观看| 播播国产欧美激情| 亚洲xxxx做受欧美| 欧美午夜女人视频在线| 亚洲午夜国产成人av电影男同| 日韩不卡中文字幕| 日韩成人av网| 久久九九国产精品怡红院| 深夜成人在线观看| 欧美激情综合色| 国产精品网红福利| 久久精品久久久久| 国产免费久久av| 日本精品视频在线播放| 国产精品久久久久久久久久| 高清一区二区三区四区五区| 欧美在线免费视频| 久久人91精品久久久久久不卡| 亚州欧美日韩中文视频| 在线视频欧美日韩精品| 91在线视频免费| 精品香蕉在线观看视频一| 色综久久综合桃花网| 91丨九色丨国产在线| 国产精品夜间视频香蕉| 欧美一区二区三区艳史| 91欧美激情另类亚洲| 亚洲精品在线看| 成人网在线免费观看| 亚洲人成欧美中文字幕| 懂色av影视一区二区三区| 亚洲区bt下载| 亚洲成人久久网| 亚洲精品suv精品一区二区| 欧美高清视频在线播放| 狠狠爱在线视频一区| 国产精品久久久久秋霞鲁丝| 欧美成人sm免费视频| 欧美国产精品人人做人人爱| 亚洲美女av在线| 亚洲综合精品伊人久久| 国产精品爽黄69天堂a| 欧美一区深夜视频| 在线国产精品播放| 亚洲欧洲美洲在线综合| 国产精品第一第二| 午夜精品久久久99热福利| 欧美性猛交xxxx免费看久久久| 奇米一区二区三区四区久久| 97香蕉超级碰碰久久免费软件| 亚洲黄色片网站| 国产亚洲欧美日韩美女| 欧美成人午夜剧场免费观看| 欧美亚洲国产日本| 成人黄色激情网| 久久九九热免费视频| 精品综合久久久久久97| 欧美日韩国产一中文字不卡| 懂色av影视一区二区三区| 91九色国产社区在线观看| 不卡在线观看电视剧完整版| 国产精品日韩精品| 久久天天躁狠狠躁夜夜av| 91精品国产自产在线| 北条麻妃在线一区二区| 精品露脸国产偷人在视频|