---- 在企業內部網中,本文提出了使用安全策略文件來設置java程序權限的一種簡單的方法。由于企業內部網中各臺計算機的位置、用途和安全性明確,更適于使用安全策略文件來設置java的權限,軟件的安裝、設置、升級和遷移都非常的方便,并且,還可以和數字簽名配合使用,更重要的是,可以細分每個java程序的權限,使用起來靈活方便。

---- Java應用程序環境的安全策略,詳細說明了對于不同的代碼所擁有的不同資源的許可,它由一個Policy對象來表達。為了讓applet(或者運行在SecurityManager下的一個應用程序)能夠執行受保護的行為,例如讀寫文件,applet(或Java應用程序)必須獲得那項操作的許可,安全策略文件就是用來實現這些許可。
---- Policy對象可能有多個實體,雖然任何時候只能有一個起作用。當前安裝的Policy對象,在程序中可以通過調用getPolicy方法得到,也可以通過調用setPolicy方法改變。Policy對象評估整個策略,返回一個適當的Permissions對象,詳細說明那些代碼可以訪問那些資源。
---- 策略文件可以儲存在無格式的ASCII文件,或Policy類的二進制文件,或數據庫中。本文僅討論無格式的ASCII文件的形式。

---- 為了能夠更好地理解下面的內容,建議在閱讀時參照\jdk1.2\jre\lib\security\java.policy文件和\jdk1.2\jre\lib\security\java.security文件的內容。
---- 1. Policy文件的語法格式與說明
---- 一個Policy文件實質上是一個記錄列表,它可能含有一個“keystore”記錄,以及含有零個或多個“grant”記錄。其格式如下:
keystore "some_keystore_url",
"keystore_type";
grant [SignedBy "signer_names"]
[, CodeBase "URL"] {
Permission permission_class_name
[ "target_name" ]
[, "action"] [, SignedBy "signer_names"];
Permission ...
};
---- 1.1"keystore"記錄
---- 一個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”。
---- 1.2"grant"記錄
---- 在Policy文件中的每一個grant記錄含有一個CodeSource(一個指定的代碼)及其permission(許可)。
---- Policy文件中的每一條grant記錄遵循下面的格式,以保留字“grant”開頭,表示一條新的記錄的開始,“Permission”是另一個保留字,在記錄中用來標記一個新的許可的開始。每一個grant記錄授予一個指定的代碼(CodeBase)一套許可(Permissions)。
---- permission_class_name必須是一個合格并存在的類名,例如java.io.FilePermission,不能使用縮寫(例如,FilePermission)。
---- target_name用來指定目標類的位置,action用于指定目標類擁有的權限。
---- target_name可以直接指定類名(可以是絕對或相對路徑),目錄名,也可以是下面的通配符:
directory/* 目錄下的所有文件
*當前目錄的所有文件
directory/-目錄下的所有文件,包括子目錄
- 當前目錄下的所有文件,包括子目錄
《ALL FILES》文件系統中的所有文件
對于java.io.FilePermission,action可以是:
read, write, delete和execute。
對于java.net.SocketPermission,action可以是:
listen,accept,connect,read,write。
---- 1.3 Policy文件中的屬性擴展(Property Expansion)
---- 屬性擴展與shell中使用的變量擴展類似,它的格式為:
"${some.property}"
實際使用的例子為:
permission java.io.FilePermission
"${user.home}", "read";
"${user.home}"的值為"d:\Project",
因此,下面的語句和上面的語句是一樣的:
permission java.io.FilePermission "
d:\Project ", "read";

---- 當初始化Policy時,首先裝載系統Policy,然后再增加用戶Policy,如果兩者都不存在,則使用缺省的Policy,即原始的沙箱模型。
---- 系統Policy文件的缺省位置為:
{java.home}/lib/security/java.policy (Solaris)
{java.home}\lib\security\java.policy (Windows)
用戶Policy文件的缺省位置為:
{user.home}/.java.policy (Solaris)
{user.home}\.java.policy (Windows)
---- 其實,在實際使用中,我們可能不會象上面介紹的那么復雜,特別是在不使用數字簽名時。這時,我們完全可以借鑒JDK 1.2提供給我們的現成的\jdk1.2\jre\lib\security\java.policy文件,根據我們的需要作相應的修改,本文就針對不使用數字簽名情況詳細說明安全策略文件的用法。
---- 下面,是一個完整的在Windows 95/98/NT下使用的.java.policy文件。在文件中,分別使用注釋的形式說明了每個“permission”記錄的用途。
// For LanServerTalk.java and LanClientTalk.java
grant {
//對系統和用戶目錄“讀”的權限
permission java.util.PropertyPermission
"user.dir", "read";
permission java.util.PropertyPermission
"user.home", "read";
permission java.util.PropertyPermission
"java.home", "read";
permission java.util.PropertyPermission
"java.class.path", "read";
permission java.util.PropertyPermission
"user.name", "read";
//對線程和線程組的操作權限
permission java.lang.RuntimePermission
"modifyThread";
permission java.lang.RuntimePermission
"modifyThreadGroup";
//操作Socket端口的各種權限
permission java.net.SocketPermission
"-", "listen";
permission java.net.SocketPermission
"-", "accept";
permission java.net.SocketPermission
"-", "connect";
permission java.net.SocketPermission "-", "read";
permission java.net.SocketPermission "-", "write";
//讀寫文件的權限
permission java.io.FilePermission "-", "read";
permission java.io.FilePermission "-", "write";
//退出系統的權限,例如System.exit(0)
permission java.lang.RuntimePermission "exitVM";
};

---- 對于windows 95/98/NT,使用.java.policy文件的方法主要有下面兩種。
---- 1. 使用缺省目錄
---- 我們可以簡單地將編輯好的.java.policy文件拷貝到windows 95/98/NT的HOME目錄,這時,所有的applet(或Java應用程序)可能都擁有某些相同的權限,使用起來簡單,但不靈活(例如:對于java.io.FilePermission ,其目標類的target_name必須使用絕對路徑),如果不是在企業內部網中使用,還可能存在一定安全隱患。
---- 2. 在命令行中指定
---- 在命令行,如果我們希望傳遞一個Policy文件給appletviewer,還可以使用"-J-Djava.security.policy"參數來指定policy的位置:
appletviewer -J-Djava.security.
policy=pURL myApplet
---- pURL為Policy文件的位置。下面,是一個實際的例子,以當前目錄的.java.policy文件所指定的安全策略運行當前目錄的LanServerTalk.html(文件中裝載并運行LanServerTalk.java):
appletviewer -J-Djava.security.policy
=.java.policy LanServerTalk.html
---- 這種方法使用靈活,特別是作為一個軟件包在企業內部網中發布時,安裝、設置和遷移軟件,基本無須修改Policy文件的內容,使用起來相當簡單,而且,安全許可的范圍控制較精細。
__________________________________________________________________________________
缺省策略實現和策略文件語法
上次修改時間: 1998 年 10 月 30 日
Java 應用程序環境的策略(對不同來源的代碼指定權限)由 Policy 對象來表示。更明確地說,就是由 Policy
類(包含在 java.security
包中)的實現抽象方法的 Policy
子類來表示。
Policy 對象所用策略信息的源位置由 Policy 實現決定。缺省 Policy 實現從靜態策略配置文件獲得自己的信息。本文檔的其余部分敘述了缺省 Policy 實現及其所讀取的策略文件中必須使用的語法。有關使用 Policy Tool 來創建策略文件(不必知道所需語法)的詳細信息,請參閱《策略工具文檔》 (for Solaris) (for Windows)。
以下是本文檔其余部分的概要:
缺省 Policy 實現
在缺省 Policy 實現中,可在一個或多個策略配置文件中指定策略。配置文件的作用是指定特定代碼源的代碼所能獲得的權限。
可利用簡單的文本編輯器或 Policy Tool 實用程序來編寫策略文件。
缺省情況下,系統上只有單個全系統策略文件和唯一的(可選)用戶策略文件。
首次調用缺省 Policy 對象的
getPermissions
方法或在任何時候調用 Policy 對象refresh
方法時,即對其進行初始化。初始化包括分析策略配置文件(請參閱策略文件語法)及組裝 Policy 對象。
缺省策略文件位置
如前所述,系統在缺省情況下具有單個全系統策略文件和唯一的用戶策略文件。
系統策略文件的缺省位置為:
java.home/lib/security/java.policy (Solaris) java.home\lib\security\java.policy (Windows)注意: java.home 指的是名為“java.home”的系統屬性的值,它指定 JDK 的安裝目錄。
系統策略文件可用于授予全系統代碼權限。與 JDK 一起安裝的
java.policy
文件可向標準擴展 (Java standard extensions) 授予全部權限,允許任何用戶在無特權要求的端口進行監聽,同時允許任何代碼讀取某些對安全不敏感的“標準”屬性(例如“os.name”和“file.separator”屬性)。用戶策略文件的缺省位置為:
user.home/.java.policy (Solaris) user.home\.java.policy (Windows)注意: user.home 指的是名為“user.home”的系統屬性的值,它指定用戶的主目錄。在 Windows 系統中,假定用戶名是 uName,“user.home”屬性的缺省值為:
C:\Winnt\Profiles\uName(多用戶 Windows NT 系統中) C:\Windows\Profiles\uName(多用戶 Windows 95 系統中) C:\Windows(單用戶 Windows 95 系統中)初始化 Policy 時,將首先加載系統策略,然后在 Policy 中添加用戶策略。如果兩種策略均不存在,則采用內置策略。該內置策略與原始的沙箱策略相同。
策略文件的位置在安全屬性文件中指定。安全屬性文件的位置為:
java.home/lib/security/java.security (Solaris) java.home\lib\security\java.security (Windows)如上所述,java.home 指示 JDK 的安裝目錄。策略文件的位置被指定為其名稱具有以下形式的屬性的值:
policy.url.n其中 n 為數字。應采用以下形式的語句行來指定每個屬性值:
policy.url.n=URL其中,URL 為 URL 規范。
例如,安全屬性文件中將把缺省系統和用戶策略文件定義為:
policy.url.1=file:${java.home}/lib/security/java.policy policy.url.2=file:${user.home}/.java.policy有關利用特殊語法(例如利用 ${java.home} 來指定 java.home 屬性值)來指定屬性值的詳細信息,請參閱屬性擴展。
實際上,用戶可以指定多個 URL(包括“http://”形式的 URL),從而加載所有指定的策略文件。也可注釋掉或更改第二個 URL,從而禁止讀取缺省用戶策略文件。
該算法自 policy.url.1 開始,然后不斷遞增直到查不到 URL 為止。因此,如果有了 policy.url.1 和 policy.url.3,就不會讀取 policy.url.3。
運行時指定其它策略文件
在執行應用程序時也可以指定附加的或不同的策略文件,方法是用“-Djava.security.policy”命令行參數來指定(該命令行參數設置 java.security.policy 屬性值)。例如,如果使用
java -Djava.security.manager -Djava.security.policy=someURL SomeApp這里 someURL 是指定策略文件位置的 URL,則除了加載安全屬性文件中指定的所有策略文件外,還會加載本方法所指定的策略文件。
注意:
- URL 可以是任何標準 URL,也可以只是當前目錄下策略文件的文件名,如下例所示:
java -Djava.security.manager -Djava.security.policy=mypolicy WriteFile- “-Djava.security.manager”參數可確保缺省安全管理器已被安裝,這樣就容易對應用程序進行策略檢查。如果應用程序 SomeApp 安裝有安全管理器,則不需要該參數。
如果使用
java -Djava.security.manager -Djava.security.policy==someURL SomeApp(請注意雙等號),就會僅使用指定的策略文件,而安全屬性文件中指出的策略文件將被忽略。
如果要將策略文件傳遞給 appletviewer,就應使用參數“-J-Djava.security.policy”,如下所示:
appletviewer -J-Djava.security.policy=someURL myApplet請注意:如果將安全屬性文件中的“policy.allowSystemProperty”屬性設置為“false”,就會忽略“-Djava.security.policy”策略文件值(對于
java
和appletviewer
命令)。缺省值為“true”。
更改 Policy 實現
可以用其它 policy 類來代替缺省 Policy 實現類,前提是前者屬于抽象 Policy 類的子類并可實現
getPermissions
方法(及其它必要的方法)。缺省 Policy 實現的更改可通過編輯安全屬性文件來完成,其中安全屬性文件指 JDK
lib/security
目錄中的java.security
文件。下面給出一種可在
java.security
中設置的屬性類型的形式:policy.provider=PolicyClassNamePolicyClassName 必須指定所需 Policy 實現類的完整名稱。該屬性的缺省安全屬性文件項如下所示:
policy.provider=sun.security.provider.PolicyFile要想自定義安全屬性文件項,可通過更改屬性值來指定另一個類,如下例所示:
policy.provider=com.mycom.MyPolicy
策略文件語法
JDK 的策略配置文件可用于指定來自特定代碼源的代碼所能獲得的權限(何種系統資源訪問類型)。
為了使 applet(或在安全管理器下運行的應用程序)能夠執行受保護的動作(例如讀寫文件),必須向 applet(或應用程序)授予進行該動作的權限。在缺省 Policy 實現中,必須由策略配置文件中的 grant 項授予該權限。有關詳細信息,請參閱以下內容及 “Java 安全體系結構規范”(唯一的例外是:代碼對位于與它自身同一 (URL) 位置并且對那一位置子目錄下的文件總是自動擁有讀權限,而無需授予明確的權限)。
策略配置文件主要包含授權項列表。其中可能包含“keystore”(密鑰倉庫)項及零個或多個“grant”(授權)項。
Keystore 項
keystore 是存放私鑰及相關數字證書(例如驗證對應的公鑰的 X.509 證書鏈)的數據庫。keytool 實用程序 (for Solaris) (for Windows) 用于創建和管理密鑰倉庫。策略配置文件中所指定的 keystore 用于查找在該文件的授權項中所指定的簽名人公鑰。如果某一授權項指定了簽名人別名(請參閱以下內容),則在策略配置文件中必須含有 keystore 項。
目前,在策略文件中只能有一個 keystore 項(第一項后的其它 keystore 項將被忽略),且該項可位于文件授權項以外的任何位置。其語法如下所示:
keystore "some_keystore_url", "keystore_type";其中“some_keystore_url”指定密鑰倉庫的 URL 位置,而“keystore_type”指定密鑰倉庫的類型。
URL 是相對于策略文件位置而言。因此,如果在安全屬性文件中按以下方式指定策略文件:
policy.url.1=http://foo.bar.com/fum/some.policy而且策略文件中含有以下項:
keystore ".keystore";就會從下列位置加載密鑰倉庫:
http://foo.bar.com/fum/.keystoreURL 也可以是絕對 URL。
keystore type 定義密鑰倉庫信息的存儲和數據格式,同時也定義用于保護密鑰倉庫中私鑰及密鑰倉庫自身完整性的算法。Sun Microsystems 所支持的缺省類型是名為“JKS”的專用密鑰倉庫類型。因此,如果密鑰倉庫類型屬于“JKS”,就無需在 keystore 項中加以指定。
授權項
通常認為執行代碼來自于某“代碼源”(由 CodeSource 類型的對象表示)。代碼源不僅包含代碼的源位置 (URL),而且還包括對包含與簽寫代碼的私鑰相對應的公鑰的證書之引用。代碼源中的證書通過用戶密鑰倉庫中的符號別名引用。
每個授權項包括一個或多個“權限項”,前面為可選
codeBase
和signedBy
名字/值對,用于指定要授予權限的代碼。授權項的基本格式如下所示:grant signedBy "signer_names", codeBase "URL" { permission permission_class_name "target_name", "action", signedBy "signer_names"; .... permission permission_class_name "target_name", "action", signedBy "signer_names"; };以上所有非斜體的項必須按原樣出現(盡管大小寫無關緊要且部分為可選項,如下所示)。 斜體項代表變量值。
授權項必須以
grant
開頭。SignedBy 和 CodeBase 域
signedBy
和codeBase
名字/值對為可選域,其間的順序無關緊要。
signedBy
值表示存儲在密鑰倉庫中的證書別名。該證書內的公鑰用于驗證代碼上的數字簽名;用戶可以向由私鑰(私鑰對應于該別名所指定的 keystore 項中的公鑰)簽名的代碼授予權限。
signedBy
的值可以是由逗號分隔的多個別名。 例如“Adam,Eve,Charles”,其含義為“Adam,Eve 和 Charles 簽名”;它們之間的關系是 AND(與)而非 OR(或)。更確切地說,“Adam 簽名的代碼”語句的含義是“JAR 文件中有含類文件的代碼,這個 JAR 文件已用密鑰倉庫中別名為 Adam 的項中與公鑰所對應的私鑰簽名”。
signedBy
域可選,這是因為如果省略該域,則表示“任何簽名人”。代碼是否有簽名或由誰簽名都沒有關系。
codeBase
值表示的是代碼源位置;用戶可向來自該位置的代碼授權。空codeBase
項表示“任何代碼”;代碼來源于何處沒有關系。注意:
codeBase
值是 URL,因此應該始終用正斜杠(而不要用反斜杠)作為目錄分隔符,即使代碼源實際在 Windows 系統上。這樣,如果 Windows 系統上代碼的源位置實際上是C:\somepath\api\
,則codeBase
策略項的外觀將如下所示:grant codeBase "file:/C:/somepath/api/" { ... }值的準確含義要取決于最后的字符。后面跟著“/”的
codeBase
codeBase
將匹配指定目錄下的所有類文件(非 JAR 文件)。后面跟著“/*”的codeBase
將匹配該目錄下的所有文件(類文件和 JAR 文件)。后面跟著“/-”的codeBase
將匹配該目錄下的所有文件(類文件和 JAR 文件)及該目錄下子目錄中的所有文件。下表說明了各種不同的情況。
下載代碼的 Codebase URL 策略中的 Codebase URL 是否匹配? java.sun.com/people/gong/ java.sun.com/people/gong 是
java.sun.com/people/gong/ java.sun.com/people/gong/ 是
java.sun.com/people/gong/ java.sun.com/people/gong/* 是
java.sun.com/people/gong/ java.sun.com/people/gong/- 是
java.sun.com/people/gong/appl.jar java.sun.com/people/gong/ 否
java.sun.com/people/gong/appl.jar java.sun.com/people/gong/- 是
java.sun.com/people/gong/appl.jar java.sun.com/people/gong/* 是
java.sun.com/people/gong/appl.jar java.sun.com/people/- 是
java.sun.com/people/gong/appl.jar java.sun.com/people/* 否
java.sun.com/people/gong/ java.sun.com/people/- 是
java.sun.com/people/gong/ java.sun.com/people/* 否
權限項
權限項必須以
permission
開頭。上述模板中的字permission_class_name
的實際值可以是特定的權限類型(例如java.io.FilePermission
或java.lang.RuntimePermission
)。"action" 對于許多權限類型而言都是必需的,例如
java.io.FilePermission
(指定允許何種類型的文件訪問權限)。 對于諸如java.lang.RuntimePermission
等權限類型則為可選項:既可以在 permission_class_name 之后的"target_name"
值中指定權限,也可以不指定權限。權限項的
signedBy
名字/值對為可選項。如果有名字/值對,則表示為已簽名權限。意即必須由給定的別名對權限類簽名,方可授予權限。例如,假定有以下授權項:grant { permission Foo "foobar", signedBy "FooSoft"; }如果將
Foo.class
權限放到 JAR 文件中,且該 JAR 文件已由與 "FooSoft" 別名所指定的證書中的公鑰相對應的私鑰簽名,或在Foo.class
是系統類(因為系統類不受策略限制)的情況下,即可授予 Foo 權限類型。權限項中出現的項目必須按指定順序出現(
permission
,permission_class_name,"target_name","action" 和signedBy
"signer_names")。分號表示項終止。大小寫對于標識符(
permission
、signedBy
、codeBase
等)來說并不重要,但對于 permission_class_name 或作為值傳遞過來的字符串而言就很重要了。有關 Windows 系統上文件路徑規范的注意事項
請注意:在指定
java.io.FilePermission
時,"target_name" 是文件路徑。在 Windows 系統上,無論何時在字符串中(而不是在 codeBase URL 中)直接指定文件路徑,路徑中都需要兩個反斜杠來代表一個實際的反斜杠,如下例所示:grant { permission java.io.FilePermission "C:\\users\\cathy\\foo.bat", "read"; };原因在于:字符串是由符號處理器 (java.io.StreamTokenizer) 來處理的。符號處理器允許將“\”用作轉義字符串(例如,“\n”表示換行),因此需要用兩個反斜杠來表示一個反斜杠。符號處理器處理完以上文件路徑字符串后,將把雙反斜杠轉換成單個反斜杠,其最終結果為:
"C:\users\cathy\foo.bat"
策略文件示例
策略配置文件中兩項的示例如下所示:
// 如果代碼由 "Duke" 簽字,則向 /tmp 中的所有文件 // 授予讀/寫訪問權限: grant signedBy "Duke" { permission java.io.FilePermission "/tmp/*", "read,write"; };// 授予所有用戶以下權限:
grant { permission java.util.PropertyPermission "java.vendor"; };
另一個示例策略配置文件如下所示。
grant signedBy "sysadmin", codeBase "file:/home/sysadmin/*" { permission java.security.SecurityPermission "Security.insertProvider.*"; permission java.security.SecurityPermission "Security.removeProvider.*"; permission java.security.SecurityPermission "Security.setProperty.*"; };本示例規定:只有滿足以下條件的代碼才能調用 Security 類中的方法以添加或刪除提供者或者設置 Security 屬性:
- 代碼將從位于本地文件系統上“/home/sysadmin/”目錄下的簽名 JAR 文件中加載。
- 可以用密鑰倉庫中別名“sysadmin”所引用的公鑰來校驗簽名。
可以忽略代碼源中兩個組件的任何一個(或兩者)。下面是忽略
codeBase
的示例:grant signedBy "sysadmin" { permission java.security.SecurityPermission "Security.insertProvider.*"; permission java.security.SecurityPermission "Security.removeProvider.*"; };如果該策略生效,則來自 JAR 文件(由 "sysadmin" 簽名)的代碼可以添加/刪除提供者,而不管 JAR 文件來源于何處。
下面是沒有簽名人的示例:
grant codeBase "file:/home/sysadmin/-" { permission java.security.SecurityPermission "Security.insertProvider.*"; permission java.security.SecurityPermission "Security.removeProvider.*"; };這里,來自本地文件系統“/home/sysadmin/”目錄下任意位置的代碼都可以添加/刪除提供者。 該代碼不必簽名。
下面是既不含
codeBase
也不含signedBy
的示例:grant { permission java.security.SecurityPermission "Security.insertProvider.*"; permission java.security.SecurityPermission "Security.removeProvider.*"; };此處,由于兩個代碼源組件均被忽略,因此任何代碼(不管來自于何處,是否已簽名或由何人簽名)都可添加/刪除提供者。
策略文件中的屬性擴展
策略文件和安全屬性文件中可以進行屬性擴展。
屬性擴展類似于擴展 shell 中的變量。也就是說,當類似
${some.property}的字符串出現在策略文件或安全屬性文件中時,它將被擴展為系統屬性的值。 例如,
permission java.io.FilePermission "${user.home}", "read";將把 "${user.home}" 擴展為使用 "user.home" 系統屬性的值。如果該屬性的值是 "/home/cathy",則以上示例等價于:
permission java.io.FilePermission "/home/cathy", "read";為了能在與平臺無關的策略文件中使用,也可采用特殊記號 "${/}"。該記號是 "${file.separator}" 的簡化表示。這種方式允許使用下列字符串:
permission java.io.FilePermission "${user.home}${/}*", "read";如果 "user.home" 屬性的值是
/home/cathy
,而且是在 Solaris 系統上,則以上字符串將轉換為:permission java.io.FilePermission "/home/cathy/*", "read";如果 "user.home" 值是
C:\users\cathy
,而且是在 Windows 系統上,則以上字符串將轉換為:permission java.io.FilePermission "C:\users\cathy\*", "read";同樣,作為一種特例,如果擴展 codebase 中的屬性,例如
grant codeBase "file:${java.home}/lib/ext/"則任何文件分隔符都將自動轉換為“/”。這樣,在 Windows 系統上,以上字符串將轉換為:
grant codeBase "file:C:/jdk1.2/lib/ext/"即使 "java.home" 被設置為
C:\jdk1.2
。因此,用戶就不必也不應該在 codeBase 字符串中使用 ${/}。策略文件中允許使用雙引號字符串的地方都可進行屬性擴展。其中包括 "signer_names"、"URL"、"target_name" 和 "action" 域。
是否允許屬性擴展由安全屬性文件中的“policy.expandProperties”屬性控制。如果該屬性為真(缺省值),則允許擴展。
請注意:不能使用嵌套屬性;嵌套屬性將無效。 例如,
"${user.${foo}}"是無效的,即使將“foo”屬性設置為“home”。原因在于屬性解析程序不能識別嵌套屬性;解析程序只是簡單地搜索第一個“${”,然后繼續搜索直到找到第一個“}”為止,同時試圖將搜索結果(這里是 "${user.$foo}")解釋為屬性。如果沒有這種屬性,則解析程序就會發生解釋失敗。
也請注意:如果在 grant 項、permission 項或 keystore 項中無法擴展某個屬性,則該項將被忽略。例如,如果在沒有定義系統屬性“foo”的情況下使用語句:
grant codeBase "${foo}" { permission ...; permission ...; };則該 grant 項中的所有權限都將被忽略。如果使用語句:
grant { permission Foo "${foo}"; permission Bar; };則將僅忽略“permission Foo...”項。最后,如果使用語句:
keystore "${foo}";則將忽略 keystore 項。
Windows 系統、文件路徑和屬性的擴展
如上所述,在 Windows 系統上,當直接在字符串中(而不是在 codeBase URL 中)指定文件路徑時,用戶需要用兩個反斜杠來代表文件路徑中一個實際的反斜杠,如下例所示:
grant { permission java.io.FilePermission "C:\\users\\cathy\\foo.bat", "read"; };原因在于:字符串是由符號處理器 (java.io.StreamTokenizer) 來處理的。符號處理器允許將“\”用作轉義字符串(例如,“\n”表示換行),因此需要用兩個反斜杠來表示一個反斜杠。符號處理器處理完以上文件路徑字符串后,將把雙反斜杠轉換成單個反斜杠,其最終結果為:
"C:\users\cathy\foo.bat"符號處理器處理完字符串后,即進行字符串中的屬性擴展。因此,如果使用字符串:
"${user.home}\\foo.bat"則符號處理器首先處理字符串,即將雙反斜杠轉換成單個反斜杠,其結果為:
"${user.home}\foo.bat"隨即擴展 ${user.home} 屬性,其最終結果為:
"C:\users\cathy\foo.bat"以上假定 "user.home" 的值是
C:\users\cathy
。當然,為實現與平臺無關,最好在開始指定字符串時不要顯式帶上斜杠,即可以用 ${/} 屬性來代替,如下例所示:"${user.home}${/}foo.bat"