---- 眾所周知,Java語言具有完善的安全框架,從編程語言,編譯器、解釋程序到Java虛擬機(jī),都能確保Java系統(tǒng)不被無效的代碼或敵對(duì)的編譯器暗中破壞,基本上,它們保證了Java代碼按預(yù)定的規(guī)則運(yùn)作。但是,當(dāng)我們需要逾越這些限制時(shí),例如,讀寫文件,監(jiān)聽和讀寫Socket,退出Java系統(tǒng)等,就必須使用數(shù)字簽名或安全策略文件(*.Policy)。

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

一. Java中安全策略的概念
---- Java應(yīng)用程序環(huán)境的安全策略,詳細(xì)說明了對(duì)于不同的代碼所擁有的不同資源的許可,它由一個(gè)Policy對(duì)象來表達(dá)。為了讓applet(或者運(yùn)行在SecurityManager下的一個(gè)應(yīng)用程序)能夠執(zhí)行受保護(hù)的行為,例如讀寫文件,applet(或Java應(yīng)用程序)必須獲得那項(xiàng)操作的許可,安全策略文件就是用來實(shí)現(xiàn)這些許可。
---- Policy對(duì)象可能有多個(gè)實(shí)體,雖然任何時(shí)候只能有一個(gè)起作用。當(dāng)前安裝的Policy對(duì)象,在程序中可以通過調(diào)用getPolicy方法得到,也可以通過調(diào)用setPolicy方法改變。Policy對(duì)象評(píng)估整個(gè)策略,返回一個(gè)適當(dāng)?shù)腜ermissions對(duì)象,詳細(xì)說明那些代碼可以訪問那些資源。

---- 策略文件可以儲(chǔ)存在無格式的ASCII文件,或Policy類的二進(jìn)制文件,或數(shù)據(jù)庫中。本文僅討論無格式的ASCII文件的形式。

二. Policy文件的格式
---- 為了能夠更好地理解下面的內(nèi)容,建議在閱讀時(shí)參照\jdk1.2\jre\lib\security\java.policy文件和\jdk1.2\jre\lib\security\java.security文件的內(nèi)容。
---- 1. Policy文件的語法格式與說明

---- 一個(gè)Policy文件實(shí)質(zhì)上是一個(gè)記錄列表,它可能含有一個(gè)“keystore”記錄,以及含有零個(gè)或多個(gè)“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"記錄
---- 一個(gè)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”。

---- 1.2"grant"記錄

---- 在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。

---- 1.3 Policy文件中的屬性擴(kuò)展(Property Expansion)
---- 屬性擴(kuò)展與shell中使用的變量擴(kuò)展類似,它的格式為:

"${some.property}"
實(shí)際使用的例子為:
permission java.io.FilePermission
"${user.home}", "read";
"${user.home}"的值為"d:\Project",
因此,下面的語句和上面的語句是一樣的:
permission java.io.FilePermission "
d:\Project ", "read";

三. 實(shí)例
---- 當(dāng)初始化Policy時(shí),首先裝載系統(tǒng)Policy,然后再增加用戶Policy,如果兩者都不存在,則使用缺省的Policy,即原始的沙箱模型。
---- 系統(tǒng)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)

---- 其實(shí),在實(shí)際使用中,我們可能不會(huì)象上面介紹的那么復(fù)雜,特別是在不使用數(shù)字簽名時(shí)。這時(shí),我們完全可以借鑒JDK 1.2提供給我們的現(xiàn)成的\jdk1.2\jre\lib\security\java.policy文件,根據(jù)我們的需要作相應(yīng)的修改,本文就針對(duì)不使用數(shù)字簽名情況詳細(xì)說明安全策略文件的用法。
---- 下面,是一個(gè)完整的在Windows 95/98/NT下使用的.java.policy文件。在文件中,分別使用注釋的形式說明了每個(gè)“permission”記錄的用途。

// For LanServerTalk.java and LanClientTalk.java

grant {
//對(duì)系統(tǒng)和用戶目錄“讀”的權(quán)限
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";

//對(duì)線程和線程組的操作權(quán)限
permission java.lang.RuntimePermission
"modifyThread";
permission java.lang.RuntimePermission
"modifyThreadGroup";

//操作Socket端口的各種權(quán)限
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";

//讀寫文件的權(quán)限
permission java.io.FilePermission "-", "read";
permission java.io.FilePermission "-", "write";

//退出系統(tǒng)的權(quán)限,例如System.exit(0)
permission java.lang.RuntimePermission "exitVM";
};

四. java.policy文件的使用
---- 對(duì)于windows 95/98/NT,使用.java.policy文件的方法主要有下面兩種。
---- 1. 使用缺省目錄

---- 我們可以簡單地將編輯好的.java.policy文件拷貝到windows 95/98/NT的HOME目錄,這時(shí),所有的applet(或Java應(yīng)用程序)可能都擁有某些相同的權(quán)限,使用起來簡單,但不靈活(例如:對(duì)于java.io.FilePermission ,其目標(biāo)類的target_name必須使用絕對(duì)路徑),如果不是在企業(yè)內(nèi)部網(wǎng)中使用,還可能存在一定安全隱患。

---- 2. 在命令行中指定

---- 在命令行,如果我們希望傳遞一個(gè)Policy文件給appletviewer,還可以使用"-J-Djava.security.policy"參數(shù)來指定policy的位置:

appletviewer -J-Djava.security.
policy=pURL myApplet

---- pURL為Policy文件的位置。下面,是一個(gè)實(shí)際的例子,以當(dāng)前目錄的.java.policy文件所指定的安全策略運(yùn)行當(dāng)前目錄的LanServerTalk.html(文件中裝載并運(yùn)行LanServerTalk.java):
appletviewer -J-Djava.security.policy
=.java.policy LanServerTalk.html

---- 這種方法使用靈活,特別是作為一個(gè)軟件包在企業(yè)內(nèi)部網(wǎng)中發(fā)布時(shí),安裝、設(shè)置和遷移軟件,基本無須修改Policy文件的內(nèi)容,使用起來相當(dāng)簡單,而且,安全許可的范圍控制較精細(xì)。

__________________________________________________________________________________

缺省策略實(shí)現(xiàn)和策略文件語法

上次修改時(shí)間: 1998 年 10 月 30 日

Java 應(yīng)用程序環(huán)境的策略(對(duì)不同來源的代碼指定權(quán)限)由 Policy 對(duì)象來表示。更明確地說,就是由 Policy 類(包含在 java.security 包中)的實(shí)現(xiàn)抽象方法的 Policy 子類來表示。

Policy 對(duì)象所用策略信息的源位置由 Policy 實(shí)現(xiàn)決定。缺省 Policy 實(shí)現(xiàn)從靜態(tài)策略配置文件獲得自己的信息。本文檔的其余部分?jǐn)⑹隽巳笔?Policy 實(shí)現(xiàn)及其所讀取的策略文件中必須使用的語法。有關(guān)使用 Policy Tool 來創(chuàng)建策略文件(不必知道所需語法)的詳細(xì)信息,請(qǐng)參閱《策略工具文檔》 (for Solaris) (for Windows)。

以下是本文檔其余部分的概要:

缺省 Policy 實(shí)現(xiàn)
缺省策略文件位置
更改 Policy 實(shí)現(xiàn)
策略文件語法
策略文件示例
策略文件中的屬性擴(kuò)展
相關(guān)文檔


缺省 Policy 實(shí)現(xiàn)

在缺省 Policy 實(shí)現(xiàn)中,可在一個(gè)或多個(gè)策略配置文件中指定策略。配置文件的作用是指定特定代碼源的代碼所能獲得的權(quán)限。

可利用簡單的文本編輯器或 Policy Tool 實(shí)用程序來編寫策略文件。

缺省情況下,系統(tǒng)上只有單個(gè)全系統(tǒng)策略文件和唯一的(可選)用戶策略文件。

首次調(diào)用缺省 Policy 對(duì)象的 getPermissions 方法或在任何時(shí)候調(diào)用 Policy 對(duì)象 refresh 方法時(shí),即對(duì)其進(jìn)行初始化。初始化包括分析策略配置文件(請(qǐng)參閱策略文件語法)及組裝 Policy 對(duì)象。

缺省策略文件位置

如前所述,系統(tǒng)在缺省情況下具有單個(gè)全系統(tǒng)策略文件和唯一的用戶策略文件。

系統(tǒng)策略文件的缺省位置為:

java.home/lib/security/java.policy  (Solaris)
java.home\lib\security\java.policy  (Windows)

注意: java.home 指的是名為“java.home”的系統(tǒng)屬性的值,它指定 JDK 的安裝目錄。

系統(tǒng)策略文件可用于授予全系統(tǒng)代碼權(quán)限。與 JDK 一起安裝的 java.policy 文件可向標(biāo)準(zhǔn)擴(kuò)展 (Java standard extensions) 授予全部權(quán)限,允許任何用戶在無特權(quán)要求的端口進(jìn)行監(jiān)聽,同時(shí)允許任何代碼讀取某些對(duì)安全不敏感的“標(biāo)準(zhǔn)”屬性(例如“os.name”和“file.separator”屬性)。

用戶策略文件的缺省位置為:

user.home/.java.policy  (Solaris)
user.home\.java.policy  (Windows)

注意: user.home 指的是名為“user.home”的系統(tǒng)屬性的值,它指定用戶的主目錄。在 Windows 系統(tǒng)中,假定用戶名是 uName,“user.home”屬性的缺省值為:

C:\Winnt\Profiles\uName(多用戶 Windows NT 系統(tǒng)中)
C:\Windows\Profiles\uName(多用戶 Windows 95 系統(tǒng)中)
C:\Windows(單用戶 Windows 95 系統(tǒng)中)

初始化 Policy 時(shí),將首先加載系統(tǒng)策略,然后在 Policy 中添加用戶策略。如果兩種策略均不存在,則采用內(nèi)置策略。該內(nèi)置策略與原始的沙箱策略相同。

策略文件的位置在安全屬性文件中指定。安全屬性文件的位置為:

java.home/lib/security/java.security  (Solaris)
java.home\lib\security\java.security  (Windows)

如上所述,java.home 指示 JDK 的安裝目錄。策略文件的位置被指定為其名稱具有以下形式的屬性的值:

policy.url.n

其中 n 為數(shù)字。應(yīng)采用以下形式的語句行來指定每個(gè)屬性值:

policy.url.n=URL

其中,URL 為 URL 規(guī)范。

例如,安全屬性文件中將把缺省系統(tǒng)和用戶策略文件定義為:

policy.url.1=file:${java.home}/lib/security/java.policy
policy.url.2=file:${user.home}/.java.policy

有關(guān)利用特殊語法(例如利用 ${java.home} 來指定 java.home 屬性值)來指定屬性值的詳細(xì)信息,請(qǐng)參閱屬性擴(kuò)展

實(shí)際上,用戶可以指定多個(gè) URL(包括“http://”形式的 URL),從而加載所有指定的策略文件。也可注釋掉或更改第二個(gè) URL,從而禁止讀取缺省用戶策略文件。

該算法自 policy.url.1 開始,然后不斷遞增直到查不到 URL 為止。因此,如果有了 policy.url.1 和 policy.url.3,就不會(huì)讀取 policy.url.3。

運(yùn)行時(shí)指定其它策略文件

在執(zhí)行應(yīng)用程序時(shí)也可以指定附加的或不同的策略文件,方法是用“-Djava.security.policy”命令行參數(shù)來指定(該命令行參數(shù)設(shè)置 java.security.policy 屬性值)。例如,如果使用

    java -Djava.security.manager -Djava.security.policy=someURL SomeApp

這里 someURL 是指定策略文件位置的 URL,則除了加載安全屬性文件中指定的所有策略文件外,還會(huì)加載本方法所指定的策略文件。

注意:

  • URL 可以是任何標(biāo)準(zhǔn) URL,也可以只是當(dāng)前目錄下策略文件的文件名,如下例所示:
        java -Djava.security.manager -Djava.security.policy=mypolicy WriteFile
    
  • “-Djava.security.manager”參數(shù)可確保缺省安全管理器已被安裝,這樣就容易對(duì)應(yīng)用程序進(jìn)行策略檢查。如果應(yīng)用程序 SomeApp 安裝有安全管理器,則不需要該參數(shù)。

如果使用

    java -Djava.security.manager -Djava.security.policy==someURL SomeApp

(請(qǐng)注意雙等號(hào)),就會(huì)使用指定的策略文件,而安全屬性文件中指出的策略文件將被忽略。

如果要將策略文件傳遞給 appletviewer,就應(yīng)使用參數(shù)“-J-Djava.security.policy”,如下所示:

    appletviewer -J-Djava.security.policy=someURL myApplet

請(qǐng)注意:如果將安全屬性文件中的“policy.allowSystemProperty”屬性設(shè)置為“false”,就會(huì)忽略“-Djava.security.policy”策略文件值(對(duì)于 javaappletviewer 命令)。缺省值為“true”。

更改 Policy 實(shí)現(xiàn)

可以用其它 policy 類來代替缺省 Policy 實(shí)現(xiàn)類,前提是前者屬于抽象 Policy 類的子類并可實(shí)現(xiàn) getPermissions 方法(及其它必要的方法)。

缺省 Policy 實(shí)現(xiàn)的更改可通過編輯安全屬性文件來完成,其中安全屬性文件指 JDK lib/security 目錄中的 java.security 文件。

下面給出一種可在 java.security 中設(shè)置的屬性類型的形式:

    policy.provider=PolicyClassName

PolicyClassName 必須指定所需 Policy 實(shí)現(xiàn)類的完整名稱。該屬性的缺省安全屬性文件項(xiàng)如下所示:

    policy.provider=sun.security.provider.PolicyFile

要想自定義安全屬性文件項(xiàng),可通過更改屬性值來指定另一個(gè)類,如下例所示:

   policy.provider=com.mycom.MyPolicy

策略文件語法

JDK 的策略配置文件可用于指定來自特定代碼源的代碼所能獲得的權(quán)限(何種系統(tǒng)資源訪問類型)。

為了使 applet(或在安全管理器下運(yùn)行的應(yīng)用程序)能夠執(zhí)行受保護(hù)的動(dòng)作(例如讀寫文件),必須向 applet(或應(yīng)用程序)授予進(jìn)行該動(dòng)作的權(quán)限。在缺省 Policy 實(shí)現(xiàn)中,必須由策略配置文件中的 grant 項(xiàng)授予該權(quán)限。有關(guān)詳細(xì)信息,請(qǐng)參閱以下內(nèi)容及 “Java 安全體系結(jié)構(gòu)規(guī)范”(唯一的例外是:代碼對(duì)位于與它自身同一 (URL) 位置并且對(duì)那一位置子目錄下的文件總是自動(dòng)擁有讀權(quán)限,而無需授予明確的權(quán)限)。

策略配置文件主要包含授權(quán)項(xiàng)列表。其中可能包含“keystore”(密鑰倉庫)項(xiàng)及零個(gè)或多個(gè)“grant”(授權(quán))項(xiàng)。

Keystore 項(xiàng)

keystore 是存放私鑰及相關(guān)數(shù)字證書(例如驗(yàn)證對(duì)應(yīng)的公鑰的 X.509 證書鏈)的數(shù)據(jù)庫。keytool 實(shí)用程序 (for Solaris) (for Windows) 用于創(chuàng)建和管理密鑰倉庫。策略配置文件中所指定的 keystore 用于查找在該文件的授權(quán)項(xiàng)中所指定的簽名人公鑰。如果某一授權(quán)項(xiàng)指定了簽名人別名(請(qǐng)參閱以下內(nèi)容),則在策略配置文件中必須含有 keystore 項(xiàng)。

目前,在策略文件中只能有一個(gè) keystore 項(xiàng)(第一項(xiàng)后的其它 keystore 項(xiàng)將被忽略),且該項(xiàng)可位于文件授權(quán)項(xiàng)以外的任何位置。其語法如下所示:

    keystore "some_keystore_url", "keystore_type";

其中“some_keystore_url”指定密鑰倉庫的 URL 位置,而“keystore_type”指定密鑰倉庫的類型。

URL 是相對(duì)于策略文件位置而言。因此,如果在安全屬性文件中按以下方式指定策略文件:

    policy.url.1=http://foo.bar.com/fum/some.policy

而且策略文件中含有以下項(xiàng):

    keystore ".keystore";

就會(huì)從下列位置加載密鑰倉庫:

    http://foo.bar.com/fum/.keystore

URL 也可以是絕對(duì) URL。

keystore type 定義密鑰倉庫信息的存儲(chǔ)和數(shù)據(jù)格式,同時(shí)也定義用于保護(hù)密鑰倉庫中私鑰及密鑰倉庫自身完整性的算法。Sun Microsystems 所支持的缺省類型是名為“JKS”的專用密鑰倉庫類型。因此,如果密鑰倉庫類型屬于“JKS”,就無需在 keystore 項(xiàng)中加以指定。

授權(quán)項(xiàng)

通常認(rèn)為執(zhí)行代碼來自于某“代碼源”(由 CodeSource 類型的對(duì)象表示)。代碼源不僅包含代碼的源位置 (URL),而且還包括對(duì)包含與簽寫代碼的私鑰相對(duì)應(yīng)的公鑰的證書之引用。代碼源中的證書通過用戶密鑰倉庫中的符號(hào)別名引用。

每個(gè)授權(quán)項(xiàng)包括一個(gè)或多個(gè)“權(quán)限項(xiàng)”,前面為可選 codeBasesignedBy 名字/值對(duì),用于指定要授予權(quán)限的代碼。授權(quán)項(xiàng)的基本格式如下所示:

  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";
  };

以上所有非斜體的項(xiàng)必須按原樣出現(xiàn)(盡管大小寫無關(guān)緊要且部分為可選項(xiàng),如下所示)。 斜體項(xiàng)代表變量值。

授權(quán)項(xiàng)必須以 grant 開頭。

SignedBy 和 CodeBase 域

signedBycodeBase 名字/值對(duì)為可選域,其間的順序無關(guān)緊要。

signedBy 值表示存儲(chǔ)在密鑰倉庫中的證書別名。該證書內(nèi)的公鑰用于驗(yàn)證代碼上的數(shù)字簽名;用戶可以向由私鑰(私鑰對(duì)應(yīng)于該別名所指定的 keystore 項(xiàng)中的公鑰)簽名的代碼授予權(quán)限。

signedBy 的值可以是由逗號(hào)分隔的多個(gè)別名。 例如“Adam,Eve,Charles”,其含義為“Adam,Eve 和 Charles 簽名”;它們之間的關(guān)系是 AND(與)而非 OR(或)。更確切地說,“Adam 簽名的代碼”語句的含義是“JAR 文件中有含類文件的代碼,這個(gè) JAR 文件已用密鑰倉庫中別名為 Adam 的項(xiàng)中與公鑰所對(duì)應(yīng)的私鑰簽名”。

signedBy 域可選,這是因?yàn)槿绻÷栽撚颍瑒t表示“任何簽名人”。代碼是否有簽名或由誰簽名都沒有關(guān)系。

codeBase 值表示的是代碼源位置;用戶可向來自該位置的代碼授權(quán)。空 codeBase 項(xiàng)表示“任何代碼”;代碼來源于何處沒有關(guān)系。

注意: codeBase 值是 URL,因此應(yīng)該始終用正斜杠(而不要用反斜杠)作為目錄分隔符,即使代碼源實(shí)際在 Windows 系統(tǒng)上。這樣,如果 Windows 系統(tǒng)上代碼的源位置實(shí)際上是 C:\somepath\api\,則 codeBase 策略項(xiàng)的外觀將如下所示:

    grant codeBase "file:/C:/somepath/api/" {
      ...
    }

codeBase

值的準(zhǔn)確含義要取決于最后的字符。后面跟著“/”的 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.jarjava.sun.com/people/gong/

java.sun.com/people/gong/appl.jarjava.sun.com/people/gong/-

java.sun.com/people/gong/appl.jarjava.sun.com/people/gong/*

java.sun.com/people/gong/appl.jarjava.sun.com/people/-

java.sun.com/people/gong/appl.jarjava.sun.com/people/*

java.sun.com/people/gong/java.sun.com/people/-

java.sun.com/people/gong/java.sun.com/people/*

權(quán)限項(xiàng)

權(quán)限項(xiàng)必須以 permission 開頭。上述模板中的字 permission_class_name 的實(shí)際值可以是特定的權(quán)限類型(例如 java.io.FilePermissionjava.lang.RuntimePermission)。

"action" 對(duì)于許多權(quán)限類型而言都是必需的,例如 java.io.FilePermission(指定允許何種類型的文件訪問權(quán)限)。 對(duì)于諸如 java.lang.RuntimePermission 等權(quán)限類型則為可選項(xiàng):既可以在 permission_class_name 之后的 "target_name" 值中指定權(quán)限,也可以不指定權(quán)限。

權(quán)限項(xiàng)的 signedBy 名字/值對(duì)為可選項(xiàng)。如果有名字/值對(duì),則表示為已簽名權(quán)限。意即必須由給定的別名對(duì)權(quán)限類簽名,方可授予權(quán)限。例如,假定有以下授權(quán)項(xiàng):

  grant {
    permission Foo "foobar", signedBy "FooSoft";
  }

如果將 Foo.class 權(quán)限放到 JAR 文件中,且該 JAR 文件已由與 "FooSoft" 別名所指定的證書中的公鑰相對(duì)應(yīng)的私鑰簽名,或在 Foo.class 是系統(tǒng)類(因?yàn)橄到y(tǒng)類不受策略限制)的情況下,即可授予 Foo 權(quán)限類型。

權(quán)限項(xiàng)中出現(xiàn)的項(xiàng)目必須按指定順序出現(xiàn)(permissionpermission_class_name,"target_name","action" 和 signedBy "signer_names")。分號(hào)表示項(xiàng)終止。

大小寫對(duì)于標(biāo)識(shí)符(permissionsignedBycodeBase 等)來說并不重要,但對(duì)于 permission_class_name 或作為值傳遞過來的字符串而言就很重要了。

有關(guān) Windows 系統(tǒng)上文件路徑規(guī)范的注意事項(xiàng)

請(qǐng)注意:在指定 java.io.FilePermission 時(shí),"target_name" 是文件路徑。在 Windows 系統(tǒng)上,無論何時(shí)在字符串中(而不是在 codeBase URL 中)直接指定文件路徑,路徑中都需要兩個(gè)反斜杠來代表一個(gè)實(shí)際的反斜杠,如下例所示:

  grant {
      permission java.io.FilePermission "C:\\users\\cathy\\foo.bat", "read";
  };

原因在于:字符串是由符號(hào)處理器 (java.io.StreamTokenizer) 來處理的。符號(hào)處理器允許將“\”用作轉(zhuǎn)義字符串(例如,“\n”表示換行),因此需要用兩個(gè)反斜杠來表示一個(gè)反斜杠。符號(hào)處理器處理完以上文件路徑字符串后,將把雙反斜杠轉(zhuǎn)換成單個(gè)反斜杠,其最終結(jié)果為:

    "C:\users\cathy\foo.bat"

策略文件示例

策略配置文件中兩項(xiàng)的示例如下所示:

  // 如果代碼由 "Duke" 簽字,則向 /tmp 中的所有文件
  // 授予讀/寫訪問權(quán)限:

  grant signedBy "Duke" {
    permission java.io.FilePermission "/tmp/*", "read,write";
  };

// 授予所有用戶以下權(quán)限:

grant { permission java.util.PropertyPermission "java.vendor"; };

另一個(gè)示例策略配置文件如下所示。

  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.*";
  };

本示例規(guī)定:只有滿足以下條件的代碼才能調(diào)用 Security 類中的方法以添加或刪除提供者或者設(shè)置 Security 屬性:

  • 代碼將從位于本地文件系統(tǒng)上“/home/sysadmin/”目錄下的簽名 JAR 文件中加載。
  • 可以用密鑰倉庫中別名“sysadmin”所引用的公鑰來校驗(yàn)簽名。

可以忽略代碼源中兩個(gè)組件的任何一個(gè)(或兩者)。下面是忽略 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.*";
  };

這里,來自本地文件系統(tǒng)“/home/sysadmin/”目錄下任意位置的代碼都可以添加/刪除提供者。 該代碼不必簽名。

下面是既不含 codeBase 也不含 signedBy 的示例:

  grant {
    permission java.security.SecurityPermission "Security.insertProvider.*";
    permission java.security.SecurityPermission "Security.removeProvider.*";
  };

此處,由于兩個(gè)代碼源組件均被忽略,因此任何代碼(不管來自于何處,是否已簽名或由何人簽名)都可添加/刪除提供者。

策略文件中的屬性擴(kuò)展

策略文件和安全屬性文件中可以進(jìn)行屬性擴(kuò)展。

屬性擴(kuò)展類似于擴(kuò)展 shell 中的變量。也就是說,當(dāng)類似

    ${some.property}

的字符串出現(xiàn)在策略文件或安全屬性文件中時(shí),它將被擴(kuò)展為系統(tǒng)屬性的值。 例如,

    permission java.io.FilePermission "${user.home}", "read";

將把 "${user.home}" 擴(kuò)展為使用 "user.home" 系統(tǒng)屬性的值。如果該屬性的值是 "/home/cathy",則以上示例等價(jià)于:

    permission java.io.FilePermission "/home/cathy", "read";

為了能在與平臺(tái)無關(guān)的策略文件中使用,也可采用特殊記號(hào) "${/}"。該記號(hào)是 "${file.separator}" 的簡化表示。這種方式允許使用下列字符串:

    permission java.io.FilePermission "${user.home}${/}*", "read";

如果 "user.home" 屬性的值是 /home/cathy,而且是在 Solaris 系統(tǒng)上,則以上字符串將轉(zhuǎn)換為:

    permission java.io.FilePermission "/home/cathy/*", "read";

如果 "user.home" 值是 C:\users\cathy,而且是在 Windows 系統(tǒng)上,則以上字符串將轉(zhuǎn)換為:

    permission java.io.FilePermission "C:\users\cathy\*", "read";

同樣,作為一種特例,如果擴(kuò)展 codebase 中的屬性,例如

    grant codeBase "file:${java.home}/lib/ext/"

則任何文件分隔符都將自動(dòng)轉(zhuǎn)換為“/”。這樣,在 Windows 系統(tǒng)上,以上字符串將轉(zhuǎn)換為:

    grant codeBase "file:C:/jdk1.2/lib/ext/"

即使 "java.home" 被設(shè)置為 C:\jdk1.2。因此,用戶就不必也不應(yīng)該在 codeBase 字符串中使用 ${/}。

策略文件中允許使用雙引號(hào)字符串的地方都可進(jìn)行屬性擴(kuò)展。其中包括 "signer_names""URL""target_name" "action" 域。

是否允許屬性擴(kuò)展由安全屬性文件中的“policy.expandProperties”屬性控制。如果該屬性為真(缺省值),則允許擴(kuò)展。

請(qǐng)注意:不能使用嵌套屬性;嵌套屬性將無效。 例如,

    "${user.${foo}}"

是無效的,即使將“foo”屬性設(shè)置為“home”。原因在于屬性解析程序不能識(shí)別嵌套屬性;解析程序只是簡單地搜索第一個(gè)“${”,然后繼續(xù)搜索直到找到第一個(gè)“}”為止,同時(shí)試圖將搜索結(jié)果(這里是 "${user.$foo}")解釋為屬性。如果沒有這種屬性,則解析程序就會(huì)發(fā)生解釋失敗。

也請(qǐng)注意:如果在 grant 項(xiàng)、permission 項(xiàng)或 keystore 項(xiàng)中無法擴(kuò)展某個(gè)屬性,則該項(xiàng)將被忽略。例如,如果在沒有定義系統(tǒng)屬性“foo”的情況下使用語句:

    grant codeBase "${foo}" {
      permission ...;
      permission ...;
    };

則該 grant 項(xiàng)中的所有權(quán)限都將被忽略。如果使用語句:

    grant {
      permission Foo "${foo}";
      permission Bar;
    };

則將僅忽略“permission Foo...”項(xiàng)。最后,如果使用語句:

    keystore "${foo}";

則將忽略 keystore 項(xiàng)。

Windows 系統(tǒng)、文件路徑和屬性的擴(kuò)展

如上所述,在 Windows 系統(tǒng)上,當(dāng)直接在字符串中(而不是在 codeBase URL 中)指定文件路徑時(shí),用戶需要用兩個(gè)反斜杠來代表文件路徑中一個(gè)實(shí)際的反斜杠,如下例所示:

    grant {
        permission java.io.FilePermission "C:\\users\\cathy\\foo.bat", "read";
    };

原因在于:字符串是由符號(hào)處理器 (java.io.StreamTokenizer) 來處理的。符號(hào)處理器允許將“\”用作轉(zhuǎn)義字符串(例如,“\n”表示換行),因此需要用兩個(gè)反斜杠來表示一個(gè)反斜杠。符號(hào)處理器處理完以上文件路徑字符串后,將把雙反斜杠轉(zhuǎn)換成單個(gè)反斜杠,其最終結(jié)果為:

    "C:\users\cathy\foo.bat"

符號(hào)處理器處理完字符串后,即進(jìn)行字符串中的屬性擴(kuò)展。因此,如果使用字符串:

    "${user.home}\\foo.bat"

則符號(hào)處理器首先處理字符串,即將雙反斜杠轉(zhuǎn)換成單個(gè)反斜杠,其結(jié)果為:

    "${user.home}\foo.bat"

隨即擴(kuò)展 ${user.home} 屬性,其最終結(jié)果為:

    "C:\users\cathy\foo.bat"

以上假定 "user.home" 的值是 C:\users\cathy。當(dāng)然,為實(shí)現(xiàn)與平臺(tái)無關(guān),最好在開始指定字符串時(shí)不要顯式帶上斜杠,即可以用 ${/} 屬性來代替,如下例所示:

    "${user.home}${/}foo.bat"