Java安全策略(Policy)
根據(jù)以前的幾篇文章我們知道,Java 2 平臺(tái)安全體系結(jié)構(gòu)背后的基本原理可以總結(jié)如下:
一個(gè)系統(tǒng)級(jí)的安全策略定義了按以保護(hù)域(protection domains.)方式組織的執(zhí)行代碼的訪問權(quán)限(按照應(yīng)用程序的需要)。安全策略用于訪問控制檢查,這是由 JVM 在運(yùn)行時(shí)執(zhí)行的。
在 Java 2 平臺(tái)中,所有的代碼,不管它是本地代碼還是遠(yuǎn)程代碼,都可以由策略來控制,此基礎(chǔ)上構(gòu)建的 Java 2 平臺(tái)安全策略設(shè)計(jì)為根據(jù) ProtectionDomain 授權(quán)訪問權(quán)限,而不是向單個(gè)的一段運(yùn)行代碼授權(quán)這種權(quán)限。因此,每一個(gè)類或者對(duì)象“屬于”一個(gè) ProtectionDomain ,安全策略對(duì)這個(gè)保護(hù)域授予了某種訪問權(quán)限。一個(gè)特定的 ProtectionDomain 封裝了一組類(例如,所有從特定位置上裝載、并用特定密鑰簽名的所有類),它們的實(shí)例將會(huì)授予同樣的一組權(quán)限。
保護(hù)域和代碼源
顯然,一定要能惟一地標(biāo)識(shí)一段運(yùn)行代碼以保證它的訪問權(quán)限沒有沖突。運(yùn)行代碼的惟一標(biāo)識(shí)屬性共有兩項(xiàng):代碼的來源(代碼裝載到內(nèi)存所用的 URL)和代碼的 signer 實(shí)體(由對(duì)應(yīng)于運(yùn)行代碼的數(shù)字簽名的一組公共密鑰指定)。這兩種特性的組合成運(yùn)行代碼的 CodeSource 。
現(xiàn)在可以提供 ProtectionDomain 的更嚴(yán)格定義了: ProtectionDomain 是一組 CodeSource 及其訪問權(quán)限。
Java 運(yùn)行時(shí)通過名為 java.security.Policy 的類(的具體擴(kuò)展)設(shè)置 ProtectionDomain 與授予它的權(quán)限之間的映射。這個(gè)類的默認(rèn)擴(kuò)展是 sun.security.provider.PolicyFile(參考jre下的java.security文件) 。它 從一個(gè)文件中獲得 CodeSource (由位置 URL 和 signer 標(biāo)識(shí)別名)與授予它的權(quán)限之間的映射。可以通過環(huán)境變量 java.security.policy 將這個(gè)文件的位置作為輸入提供給 JVM。 Policy 類提供了一個(gè)名為 getPermissions() 的方法,可以調(diào)用它以獲得授予特定 CodeSource 的一組權(quán)限。
一個(gè)類與 其 ProtectionDomain 之間的映射是在類第一次裝載時(shí)由一個(gè)名為 SecureClassLoader 的特殊類裝載設(shè)置的。在 Java 2 平臺(tái) SDK 1.4 中, ProtectionDomain 可以同時(shí)封裝(通過其構(gòu)造函數(shù)傳遞的)靜態(tài)權(quán)限和動(dòng)態(tài)權(quán)限,以前版本權(quán)限必須在構(gòu)建時(shí)就已經(jīng)知道。
運(yùn)行時(shí)訪問檢查
由一個(gè)名為 SecurityManager 的類負(fù)責(zé)實(shí)施系統(tǒng)安全策略。在默認(rèn)情況下不安裝安全管理器,必須通過一個(gè)在啟動(dòng)時(shí)傳遞給 JVM 的、名為 java.security.manager 的環(huán)境變量顯式地指定。任何應(yīng)用程序都可找到安裝的 SecurityManager 并調(diào)用它相應(yīng)的 check<XXX> 方法。如果所要求的權(quán)限在給定運(yùn)行時(shí)上下文中是授予的,那么調(diào)用將無聲地返回。如果權(quán)限沒有授予,那么將拋出一個(gè) java.security.AccessControlException 。
Java 2 平臺(tái)安全體系結(jié)構(gòu)通過引入一個(gè)名為 AccessController ,對(duì) SecurityManager 類進(jìn)行的所有 check<XXX> 方法調(diào)用都解釋為相應(yīng)的 Permission 對(duì)象,并將它作為輸入?yún)?shù)傳遞給 AccessController 類的 checkPermission() 方法
訪問檢查方案
權(quán)限的算法是要計(jì)算所有權(quán)限的交集,確定權(quán)限集的交集的算法是在 AccessController 類的 checkPermission 方法中間接實(shí)現(xiàn)的,屬于能力更低的域的類不能通過調(diào)用屬于能力更高的域的類而變得更強(qiáng)大,而屬于能力更高的域中的類會(huì)在調(diào)用能力更低的類時(shí)損失其能力
Policy File Syntax
學(xué)習(xí)時(shí)參照"jre"lib"security"java.policy文件
一個(gè)Policy文件實(shí)質(zhì)上是一個(gè)記錄列表,它可能含有一個(gè)“keystore”記錄,以及含有零個(gè)或多個(gè)“grant”記錄。
其格式如下:
keystore "some_keystore_url", "keystore_type", "keystore_provider";
keystorePasswordURL "some_password_url";
“keystore”是一個(gè)私有密鑰(private keys)數(shù)據(jù)庫和相應(yīng)的數(shù)字簽名,例如X.509證書。Policy文件中可能只有一條keystore記錄(也可能不含有該記錄),它可以出現(xiàn)在文件中g(shù)rant記錄以外的任何地方。Policy配置文件中指定的keystores用于尋找grant記錄中指定的、簽名者的公共密鑰(public keys),如果任何grant記錄指定簽名者(signer_names),那么,keystore記錄必須出現(xiàn)在policy配置文件中。
"some_keystore_url"是指keystore的URL位置,"keystore_type"是指keystore的類型。第二個(gè)選項(xiàng)是可選項(xiàng),如果沒有指定,該類型則假定由安全屬性文件(java.security)中的"keystore.type"屬性來確定。keystore類型定義了keystore信息的存儲(chǔ)和數(shù)據(jù)格式,用于保護(hù)keystore中的私有密鑰和keystore完整性的算法。Sun Microsystems支持的缺省類型為“JKS”。
grant signedBy "signer_names", codeBase "URL",
principal principal_class_name "principal_name",
principal principal_class_name "principal_name",
{
permission permission_class_name "target_name", "action",
signedBy "signer_names";
permission permission_class_name "target_name", "action",
signedBy "signer_names";

};
在Policy文件中的每一個(gè)grant記錄含有一個(gè)CodeSource(一個(gè)指定的代碼)及其permission(許可)。
Policy文件中的每一條grant記錄遵循下面的格式,以保留字“grant”開頭,表示一條新的記錄的開始,“Permission”是另一個(gè)保留字,在記錄中用來標(biāo)記一個(gè)新的許可的開始。每一個(gè)grant記錄授予一個(gè)指定的代碼(CodeBase)一套許可(Permissions)。
permission_class_name必須是一個(gè)合格并存在的類名,例如java.io.FilePermission,不能使用縮寫(例如,F(xiàn)ilePermission)。
target_name用來指定目標(biāo)類的位置,action用于指定目標(biāo)類擁有的權(quán)限。
target_name可以直接指定類名(可以是絕對(duì)或相對(duì)路徑),目錄名,也可以是下面的通配符:
directory/* 目錄下的所有文件
*當(dāng)前目錄的所有文件
directory/-目錄下的所有文件,包括子目錄
- 當(dāng)前目錄下的所有文件,包括子目錄
《ALL FILES》文件系統(tǒng)中的所有文件
對(duì)于java.io.FilePermission,action可以是:read, write, delete和execute。
對(duì)于java.net.SocketPermission,action可以是:listen,accept,connect,read,write。
The exact meaning of a codeBase value depends on the characters at the end. A codeBase with a trailing "/"
matches all class files (not JAR files) in the specified directory. A codeBase with a trailing "/*" matches
all files (both class and JAR files) contained in that directory. A codeBase with a trailing "/-" matches
all files (both class and JAR files) in the directory and recursively all files in subdirectories contained
in that directory. The following table illustrates the different cases.
/ 表示所有的class文件(不包括Jar,不包括子目錄)
/* 表示所有的class文件(包括Jar,不包括子目錄)
/- 表示所有的class文件(包括Jar,包括子目錄)
Policy文件中的屬性擴(kuò)展(Property Expansion)
屬性擴(kuò)展與shell中使用的變量擴(kuò)展類似,它的格式為:
permission java.io.FilePermission
"${user.home}", "read";
具體詳細(xì)使用請參考:Policy官方文檔:
Default Policy Implementation and Policy File Syntax
參考資源:
http://www.ibm.com/developerworks/cn/java/j-javaauth/
http://www.ibm.com/developerworks/cn/java/j-jaas/
http://java.sun.com/j2se/1.5.0/docs/guide/security/PolicyFiles.html#DefaultImpl
http://www.infosecurity.org.cn/article/websec/java/23218.html