Windows 完整性機制設計
Windows 完整性機制是 Windows 安全性架構的延伸模組,其以核心中的安全性參考監視器為基礎。 安全性參考監視器會藉由比較安全性存取權杖中的使用者和群組 SID 與物件安全性描述元 ACL 中授與的存取權限,來強制執行存取控制。 完整性機制會將完整性層級新增至安全性存取權杖,並將強制標籤存取控制專案新增至安全性描述項中的系統 ACL (SACL) 。
完整性機制的主要部分包括:
- 預先定義的完整性層級及其標記法。
- 限制存取權限的完整性原則。
- 指派給安全性存取權杖的完整性層級。
- 強制標籤存取控制專案。
- 指派給物件的強制標籤。
- AccessCheck 和核心模式 SeAccessCheck API 內的完整性限制。
以下會更詳細地說明這些部分。 Windows 完整性機制一律有效,與其他安全性原則選項無關。 完整性層級檢查,例如存取控制檢查,不是選擇性的。 沒有安全性原則選項可停用完整性層級檢查。 雖然完整性機制支援 UAC,但是當安全性群組原則停用 UAC 時,完整性機制仍然有效。
完整性層級
Windows 會使用 SID 定義完整性層級。 使用 SID 來表示完整性層級,可讓您輕鬆地將完整性機制整合到現有的安全性資料結構中,而不需要變更程式碼。 完整性層級 SID 的格式如下:S-1-16-xxxx。 表 1 顯示完整性層級 SID 的元件。
表 1 完整性層級 SID 識別碼授權單位值
值 | 描述 |
---|---|
16 |
代表強制標籤授權單位 (SECURITY_MANDATORY_LABEL_AUTHORITY) 。 |
xxxx |
表示 (RID) 欄位的相對識別碼,該欄位為完整性層級。 RID 是代表完整性層級的十六進位值。 |
Windows Vista 中有四個主要完整性層級,具有四個對應的值。 較低的值表示較低的完整性層級或較低的信任層級。 這些值定義于標頭檔 winnt.h 中。 表 2 顯示定義的完整性層級及其對應的值。
表 2 定義完整性層級和對應值
值 | Description | 符號 |
---|---|---|
0x0000 |
不受信任的層級 |
SECURITY_MANDATORY_UNTRUSTED_RID |
0x1000 |
低完整性層級 |
SECURITY_MANDATORY_LOW_RID |
0x2000 |
中完整性層級 |
SECURITY_MANDATORY_MEDIUM_RID |
0x3000 |
高完整性層級 |
SECURITY_MANDATORY_HIGH_RID |
0x4000 |
系統完整性層級 |
SECURITY_MANDATORY_SYSTEM_RID |
中完整性層級 SID 的範例是此字串:S-1-16-8192。 RID 值為 8192 是與 0x2000 相等的十進位值。
RID 會以0x1000間隔分隔,以允許日後定義其他層級。 分隔也允許將完整性層級指派給稍微高於中型的進程:例如,達到特定的系統設計目標。
定義的完整性層級 SID 具有與其相關聯的字串名稱值。 使用 API LookupAccountSID 會傳回每個完整性層級 SID 的字串名稱。 表 3 顯示完整性層級的字串名稱。
表 3 完整性層級字串名稱
完整性層級 SID | 名稱 |
---|---|
S-1-16-4096 |
強制標籤\低強制層級 |
S-1-16-8192 |
強制標籤\中強制層級 |
S-1-16-12288 |
強制標籤\高強制層級 |
S-1-16-16384 |
強制標籤\系統強制層級 |
完整性層級也會在安全性描述項定義語言 (SDDL) 中定義為 SID 字串。 SDDL 會定義 ConvertSecurityDescriptorToStringSecurityDescriptor 和 ConvertStringSecurityDescriptorToSecurityDescriptor 函式用來將安全性描述元描述項描述項描述為文字字串的字串格式。 語言也會定義字串元素,以描述安全性描述元元件中的資訊。 使用 SDDL 定義完整性層級,可方便在建立物件時定義物件的完整性層級。 如需完整性層級之 SID 字串的詳細資訊,請參閱 Windows 完整性機制資源。 強制標籤的 SDDL 支援說明于 附錄 A:強制標籤的 SDDL。
Windows Vista 使用安全性存取權杖中的完整性層級 SID 來代表主體完整性層級,並使用安全性描述項中強制標籤 ACE 中的完整性層級 SID 來代表物件完整性層級。
完整性原則
Windows 完整性機制會使用簡單原則來決定如何在物件上使用強制標籤,以限制可供較低完整性主體使用的存取層級。 這表示原則會限制允許較低完整性層級物件擁有較高完整性層級物件的存取類型。 表 4 顯示兩個原則類別。
表 4 完整性原則類別
類別 | 描述 |
---|---|
存取權杖強制原則 |
在存取權杖中設定,並判斷強制原則套用至主體的方式,該主體會以存取權杖表示。 |
強制標籤原則 |
在必要標籤中設定 ACE (,如下所述) 物件,並決定如何限制對物件的存取。 |
評估安全性實體物件的存取權限時,會使用完整性原則檢查。 原則會決定存取權限在完整性層級的限制方式。
強制存取權杖原則
表 5 顯示 Windows Vista 中定義的強制存取權杖原則。
表 5 Windows Vista 中的強制存取權杖原則
原則 | 描述 |
---|---|
TOKEN_MANDATORY_NO_WRITE_UP |
指派給所有存取權杖的預設原則。 此原則會將此主體的寫入權限限制為較高完整性層級的任何物件。 |
TOKEN_MANDATORY_NEW_PROCESS_MIN |
控制將完整性層級指派給子進程的行為。 一般而言,當父進程存取權杖指派給子系時,子進程會繼承父進程的完整性層級。 使用NEW_PROCESS_MIN原則時,子進程的完整性層級將是父存取權杖的最小完整性層級,或新進程可執行檔的物件完整性層級。 此原則預設會在所有存取權杖中設定。 |
範例可以描述NEW_PROCESS_MIN原則。 假設有稱為 lowcalc.exe 的可執行程式。 程式檔會指派低完整性標籤。 從命令提示字元中,使用者執行lowcalc.exe。 父進程cmd.exe是在中完整性層級執行。 因為影像檔lowcalc.exe具有低完整性標籤,所以NEW_PROCESS_MIN原則會將新程式的完整性層級 lowcalc 設定為 low。 這在設計 應用程式以低完整性層級執行一節的下列範例中說明。
強制標籤原則
強制標籤原則會定義為強制標籤存取控制專案的 遮罩 欄位中 (位) 旗標。 這些原則旗標會決定套用至較低完整性主體的存取權限限制。 表 6 顯示 Windows Vista 中定義的強制標籤原則。
表格 6 Windows Vista 中的強制標籤原則
原則 | 描述 |
---|---|
SYSTEM_MANDATORY_POLICY_NO_WRITE_UP |
所有物件強制標籤的預設原則。 旗標相當於NO_WRITE_UP存取權杖原則。 此原則會以較低完整性層級的主體來限制物件的寫入權限。 |
SYSTEM_MANDATORY_POLICY_NO_READ_UP |
以較低完整性層級的主體限制對物件的讀取存取。 例如,原則可用來限制對進程的虛擬記憶體位址空間的讀取存取。 |
SYSTEM_MANDATORY_POLICY_NO_EXECUTE_UP |
限制主體對物件執行存取,其完整性層級較低。 例如,原則是用來限制 COM 類別的啟動啟用許可權,方法是降低完整性主體。 |
這些已定義的原則符合 Windows Vista 的設計目標。 完整性機制的架構允許未來擴充,方法是定義其他原則選項,以控制不同完整性層級的主體和物件之間的存取權限。
完整性原則如何對應至一般許可權
強制原則檢查會在 AccessCheck 安全性函式中發生。 AccessCheck (和 SeAccessCheck 在核心模式中,) 做為GENERIC_MAPPING結構的其中一個函式參數。 呼叫端所提供的泛型對應會將物件特定的存取權限對應至讀取、寫入和執行的泛型類別。 強制標籤原則會根據一般類別實作允許存取的限制。 針對特定物件類型,GENERIC_MAPPING會與強制原則通訊,以檢查禁止哪些特定存取權限。
如果傳遞至 AccessCheck 呼叫的GENERIC_MAPPING結構都是零, (0) ,則泛型對應是未定義的。 未定義泛型對應時,強制原則檢查會限制較低完整性主體的所有存取權限。 針對私人物件安全性使用 AccessCheck 並傳遞所有零GENERIC_MAPPING結構的資源管理員將會看到 拒絕存取 錯誤。 需要對 Resource Manager 應用程式進行程式碼變更,才能將物件類型特定的存取權限對應至強制原則強制執行的一般存取權限。
如何將完整性層級指派給存取權杖
安全性存取權杖是核心使用的內部資料結構。 安全性存取權杖包含與許可權、群組成員資格和其他安全性相關詳細資料對應的不同資訊值。 當使用者以互動方式登入 Windows,或網路驗證發生時,就會發生存取權杖初始化。 初始化存取權杖時,除了其他值之外,還會新增使用者的 SID、群組 SID 和許可權。 當存取權杖初始化時,Windows Vista 會指派存取權杖的完整性層級。
核心會將存取權杖指派給每個進程和執行緒。 進程的主要存取權杖包含與該程式相關聯的完整性層級。 在 Windows 完整性機制中,程式的完整性層級稱為主體完整性層級。 如果應用程式的存取權杖包含中完整性 SID,則應用程式程式會在中完整性層級執行。 在相同使用者帳戶下執行的多個應用程式進程會指派相同的主要存取權杖。 這就是每個應用程式指派相同完整性層級的方式。
完整性層級會根據存在於TOKEN_GROUPS結構中的特定群組 SID,指派給存取權杖。 Windows 核心會根據特定的內建使用者或群組帳戶指派完整性層級。 Windows Vista 會指派具有本機系統帳戶 SID 的存取權杖,其中存在系統的完整性層級、具有本機 Administrators 群組 SID 的存取權杖已獲指派高完整性層級,而標準使用者帳戶的存取權杖會獲指派中度的完整性層級。
表 7 根據特定 SID 的存在,顯示存取權杖的完整性層級指派。
表 7 連結至特定 SID 的完整性層級
存取權杖中的 SID | 指派的完整性層級 |
---|---|
LocalSystem |
系統 |
LocalService |
系統 |
NetworkService |
系統 |
系統管理員 |
高 |
Backup Operators |
高 |
Network Configuration Operators |
高 |
Cryptographic Operators |
高 |
驗證的使用者 |
中 |
所有人 (World) |
低 |
匿名 |
未受信任 |
完整性層級會針對在不同存取層級上執行的應用程式定義不同層級的信任度。 Windows Vista 中的大部分應用程式會在中度完整性層級的標準使用者存取層級執行。 中型完整性層級的應用程式不會對它們與其他應用程式互動的方式,以及與中完整性層級的資料互動的任何限制。 需要系統管理許可權的特定工作或應用程式會以高完整性層級執行。 系統服務會在系統完整性層級執行,因為其能夠與預設桌面互動,而且通常會以強大的系統許可權執行。 一些設計成以最少許可權執行的應用程式,例如受保護的模式 Internet Explorer,可以低完整性層級執行。
某些系統管理 Windows 許可權只能指派給至少具有高完整性層級的存取權杖。 如果存取權杖完整性層級低於高,則不允許特定系統管理許可權,而且會從存取權杖中移除。 與高完整性層級相關聯的系統管理許可權如下:
- SE_CREATE_TOKEN_PRIVILEGE
- SE_TCB_PRIVILEGE
- SE_TAKE_OWNERSHIP_PRIVILEGE
- SE_BACKUP_PRIVILEGE
- SE_RESTORE_PRIVILEGE
- SE_DEBUG_PRIVILEGE
- SE_IMPERSONATE_PRIVILEGE
- SE_RELABEL_PRIVILEGE
- SE_LOAD_DRIVER_PRIVILEGE
建立子進程時,應用程式可以將低完整性層級指派給重複的存取權杖。 如果可執行檔程式影像檔案具有低強制標籤,Windows 可能會執行具有低完整性層級的應用程式程式。 本文稍後會說明這些功能。
如何取得存取權杖的完整性層級
完整性層級會使用 [TOKEN_GROUPS] 欄位儲存在存取權杖中。 TOKEN_GROUPS 結構是識別該使用者帳戶群組成員資格的 SID 和屬性清單。 存取權杖完整性層級也會使用 SID 屬性在群組清單中識別。 SID_AND_ATTRIBUTES 結構包含完整性層級 SID,並使用SE_GROUP_INTEGRITY和SE_GROUP_INTEGRITY_ENABLED屬性來識別完整性層級。
您可以使用 GetTokenInformation API,從存取權杖擷取存取權杖完整性層級。 GetTokenInformation 具有參數,表示要擷取哪些存取權杖資訊類別。 TOKEN_INFORMATION_CLASS參數具有完整性層級 TokenIntegrityLevel 的已定義值。 傳回的資料結構是TOKEN_MANDATORY_LABEL類型。
判斷進程的完整性層級
開啟進程的存取權杖控制碼。
取得存取權杖的完整性層級。
比較完整性層級 SID 與系統定義的完整性層級 RID。
取得存取權杖完整性層級的範例程式碼會顯示在附錄 D 中。
如何檢視存取權杖的完整性層級
您可以使用公開進程安全性詳細資料的工具來檢視進程的安全性存取權杖完整性層級,例如來自 SysInternals.com 的進程總管。 下圖顯示 [進程總管] 中的顯示,其中 [完整性層級] 資料行已新增至檢視 (右側) 。
圖 1 進程總管中的完整性層級
如果我們查看特定進程的安全性屬性,例如 explorer.exe,[進程總管] 會在進程安全性存取權杖中定義的群組清單中顯示完整性層級。 下圖顯示指派給進程存取權杖的強制標籤/中強制層級,explorer.exe。
圖 2 Explorer.exe為中完整性層級程式
如何設定存取權杖的完整性層級
應用程式通常不需要變更進程完整性層級的值。 應用程式通常不需要變更安全性存取權杖中的任何值。 不過,在某些情況下,支援不同完整性層級之本機用戶端的服務可能會選擇在較低完整性層級執行工作。 模擬是在較低完整性層級執行服務執行緒的其中一種方式。 當服務執行緒模擬本機用戶端時,模擬執行緒具有用戶端的安全性內容,包括用戶端在相同本機電腦上執行時的完整性層級。
另一種應用程式可以執行作業的方式,例如在較低的完整性層級建立一組檔案和登錄機碼,就是設定目前線程存取權杖的 TokenIntegrityLevel。 新的完整性層級不能高於進程的主要存取權杖中的完整性層級。
線上程上設定存取權杖完整性層級的值
呼叫 OpenThreadToken 以取得存取權杖的控制碼。
使用TokenIntegrityLevel的 TOKEN_INFORMATION_CLASS參數值呼叫GetTokenInformation,以儲存目前的執行緒完整性層級。
使用TokenIntegrityLevel的 TOKEN_INFORMATION_CLASS參數值呼叫SetTokenInformation。
由於進程位址空間內不同完整性層級的執行緒之間沒有安全性界限,因此應用程式設計工具必須考慮在較低完整性進程執行之執行緒中執行程式碼的潛在安全性風險。 大部分的應用程式可能發現建立在較低完整性層級執行的個別進程會比較簡單,以執行較低完整性的工作。
如何設定 TokenIntegrityLevel 並在較低完整性層級建立進程的範例,如如何設定存取權杖的完整性層級所示。
強制標籤 ACE
Windows 完整性機制會定義新的 ACE 類型,即系統強制標籤 ACE。 強制標籤 ACE 用來代表物件安全描述元中物件的強制標籤。 強制標籤包含完整性層級和相關聯的完整性原則。 強制標籤 ACE 只會在安全性描述元的系統 ACL 或 SACL 中使用。 SACL 是安全性描述元中的個別欄位,與任意 ACL (DACL) 。
圖 3 安全性描述項欄位
選擇性 ACL 包含物件的使用者和群組存取權限。 任何使用者或群組都可以使用WRITE_DAC物件存取權限對 DACL 進行更新。 任意 ACL 可以更頻繁地由不同的使用者更新。 完整性機制的設計目標之一,就是安全性系統應該在強制標籤套用至物件之後,使用 物件維護標籤。 在物件安全性描述元中強制執行適當的強制標籤,對設計來管理 ACL 的應用程式幾乎沒有任何影響,可藉由將強制標籤放在系統 ACL 中來完成,其中主要是在安全性系統的控制之下。 強制標籤在邏輯上與 SACL 中的系統稽核專案分開。 必要標籤在 SACL 中之前或遵循系統稽核專案之前並不需要順序。
強制標籤 ACE 類似于允許的存取 ACE,因為它包含 ACE 標頭、存取遮罩和 SID。 強制標籤 ACE 的 SID 部分包含完整性層級 SID。 表 8 顯示 ACE 標頭中的欄位。
ACE 標頭中包含的表格 8 欄位
ACE 標頭欄位 | 值 |
---|---|
AceType |
SYSTEM_MANDATORY_LABEL_ACE_TYPE |
AceFlags |
定義強制標籤 ACE 類型繼承的控制項旗標 |
AceSize |
必要標籤 ACE 的大小 |
必要的標籤 ACE 包含 遮罩 欄位。 遮罩是用來定義強制原則,以決定套用至處理常式 (或主體的存取權限限制,或) 較低完整性層級的主體。 Windows Vista 中廣泛使用的範例原則是NO_WRITE_UP原則。 強制標籤 ACE 遮罩中的NO_WRITE_UP原則旗標表示存取權杖中具有較低完整性層級的主體 () 比物件上強制標籤中完整性層級 SID 更受限,無法取得物件的一般寫入存取權。
物件上只有一個有效的強制標籤。 如果安全性描述項在 SACL 中取得一個以上的強制標籤,SACL 中的第一個強制標籤 ACE 就是物件的有效標籤。
如需必要標籤 ACE 的詳細資訊,請參閱 Windows 完整性機制資源。
讀取強制標籤 ACE
Windows Vista 會使用安全性函式 GetSecurityInfo,從物件讀取必要的標籤資訊。 GetSecurityInfo 會從 物件取得擁有者、群組、DACL 或 SACL 資訊。 GetSecurityInfo 的SECURITY_INFORMATION參數會決定傳回安全性描述元的哪個部分。 Windows Vista 會定義新的安全性資訊值,LABEL_SECURITY_INFORMATION,用來從 SACL 傳回強制標籤 ACE。 如果呼叫 GetSecurityInfo 指定SACL_SECURITY_INFORMATION,則只會傳回 SACL 中的系統稽核 ACE,而不是必要的標籤 ACE。
讀取物件上必要標籤 ACE 所需的存取權限是READ_CONTROL標準存取權限。 一般而言,需要ACCESS_SYSTEM_SECURITY存取權限,才能取得或設定 SACL 中的資訊。 只有在存取權杖中啟用SE_SECURITY_NAME許可權時,才會授與ACCESS_SYSTEM_SECURITY。 從 SACL 讀取強制標籤不需要SE_SECURITY_NAME許可權或ACCESS_SYSTEM_SECURITY存取權限。
設定強制標籤 ACE
Windows Vista 會使用 Security 函式 SetSecurityInfo 來變更物件的必要標籤資訊。 建立物件時,安全性子系統會設定物件的強制標籤。 SetSecurityInfo 的SECURITY_INFORMATION參數必須包含LABEL_SECURITY_INFORMATION,才能變更安全性描述元中的強制標籤。
在物件建立時指派的必要標籤通常是物件的正確完整性層級,而且不需要變更強制標籤。 不過,當應用程式設計成支援不同完整性層級的多個用戶端進程時,可能會有應用程式設計需求來變更物件的完整性層級。
在安全性描述項的 SACL 中變更必要標籤 ACE 所需的許可權WRITE_OWNER。 將強制標籤寫入 SACL 不需要SE_SECURITY_NAME許可權或ACCESS_SYSTEM_SECURITY存取權限。 強制標籤中的完整性層級可以設定為小於或等於主體完整性層級的值。
最常見的變更是降低物件的完整性層級,以允許較低的完整性應用程式進程具有修改存取權。 例如,中完整性層級的應用程式必須與另一個在低完整性層級執行的應用程式進程同步處理。 中型完整性程式會建立具名 mutex 物件,並將必要標籤指派為低,以允許較低的完整性程式開啟 mutex 以發出事件訊號。
Relabel 許可權
Windows 完整性機制會定義新的 Windows 安全性許可權,SE_RELABEL_NAME。 在安全性存取權杖中啟用時,重新標籤安全性許可權可讓主體將物件的強制標籤設定為比主體存取權杖中完整性層級更高的完整性層級。 Windows Vista 的預設安全性原則不會將此許可權指派給任何使用者或群組。 許可權的設計目的是解決系統管理員程式在高完整性層級執行時需要變更或指派系統完整性層級物件的必要標籤案例。 Windows Vista 沒有任何需要或使用 relabel 許可權的工作。
Windows 如何將強制標籤指派給物件
Windows 會在建立物件安全性描述元時,將強制標籤指派給安全性實體物件。 新物件的完整性層級會以下列三種方式之一指派:
- 安全性子系統會在為物件建立安全性描述項時,將強制標籤指派給物件。
- 建立程式會在使用函式建立物件時,將明確的強制標籤指定為安全性屬性,例如 CreateFile。
- 父容器會定義可繼承的強制標籤 ACE,此標籤會套用至容器中建立的子物件。
若要瞭解如何指派物件完整性層級,最簡單的方式是假設每個物件都指派了與建立進程 (或執行緒) 之主體完整性層級相同的強制標籤。 不過,根據物件類型和主體完整性層級,一般概念有例外。 例外狀況是當啟用或停用各種安全性原則,例如 UAC 等安全性原則時,支援其他系統需求所需的設計選擇結果。
強制標籤可以套用至所有根據安全性描述元具有存取控制的安全性實體物件。 有許多類型的安全性實體物件,包括進程和執行緒物件、具名物件,以及檔案或登錄機碼等持續性物件。 Windows Vista 不會在建立物件時,將明確強制標籤指派給所有物件類型。 安全性子系統在物件建立時指派強制標籤的物件類型如下:
- 處理序
- Thread
- 存取權杖
- 工作 (Job)
所有其他物件類型都有隱含預設值或繼承的必要標籤。 回想一下,在存取權杖初始化期間,完整性層級會指派給互動式登入期間建立的安全性存取權杖。 代表使用者登入啟動的第一個程式是userinit.exe,這會啟動殼層程式,explorer.exe。 Userinit.exe是由使用 CreateProcessAsUser 呼叫並傳入互動式登入使用者的存取權杖的系統服務 (Winlogon) 啟動。
CreateProcessAsUser 會建立進程物件和初始執行緒,以及其他專案。 建立進程物件時,該程式的安全性描述項會從指派為新進程主要存取權杖的存取權杖中指派完整性層級。 當userinit.exe呼叫 CreateProcess 以啟動殼層時,會初始化explorer.exe的進程物件。 進程物件包含安全性描述項和主要存取權杖。 explorer.exe程式上的強制標籤會設定為建立進程的完整性層級,userinit.exe為中。 explorer.exe的主要存取權杖繼承自建立父進程、userinit.exe,且完整性層級為中。 當explorer.exe進程建立新的執行緒時,執行緒物件會獲得安全性描述項,而安全性子系統會根據建立進程的完整性層級,將完整性層級指派給執行緒物件。 explorer.exe進程內的執行緒物件會指派中度的完整性層級,這是建立進程之主要存取權杖的完整性層級。
注意
存取權杖物件是具有其本身安全性描述元的安全性實體物件。 權杖的安全性描述元是用來判斷 OpenProcessToken 或 OpenThreadToken 函式期間允許的存取。 存取權杖物件在存取權杖物件上的安全性描述項中具有強制標籤。 存取權杖也包含存取權杖群組清單中的完整性層級 SID,代表主體完整性層級。
藉由一律將強制標籤指派給處理、執行緒、權杖和工作物件,完整性機制可防止較低完整性層級的相同使用者存取這些物件類型,以及修改其內容或行為,例如插入 DLL 或模擬較高層級存取權杖。
預設完整性層級
並非所有物件類型都會在安全性描述元中指派強制標籤 ACE。 如果安全性描述項中有強制標籤 ACE,則稱為明確強制標籤。 如果沒有強制標籤 ACE 存在,安全性子系統會在強制原則檢查期間使用該物件的隱含預設強制標籤。 預設強制標籤會為所有安全性實體物件指派中型完整性層級。 如果未在安全性描述元中定義強制標籤,則隱含的預設強制標籤會套用至所有物件類型。
媒體的預設物件完整性層級與預設強制原則NO_WRITE_UP結合,藉由主旨完整性層級小於中型的進程來限制對所有物件的存取。 預設的必要標籤和原則可防止低完整性不受信任的進程修改系統上的任何使用者或系統檔案或登錄機碼,否則可能會允許 DACL 中的任意寫入存取。
建立 NTFS 檔案系統物件和登錄機碼時,不會自動加上標籤。 從舊版 Windows 升級至 Windows Vista 之後,這些物件沒有強制標籤。 非 NTFS 檔案系統上的檔案 (CDFS 或 FAT32) 沒有安全性描述項,而且沒有安全性描述項,而且沒有完整性層級。 每個安全性描述元都必須有隱含的強制標籤。
具有主體完整性層級或更高層級的處理常式,會在沒有明確標籤的情況下建立檔案和登錄機碼。 因此,由高或系統完整性層級進程所建立的檔案系統和登錄物件具有隱含的中度標籤。 使用強制標籤的應用程式可以在建立物件時定義明確的標籤。 不過,Windows Vista 預設不會將高於中完整性層級的標籤指派給檔案系統或登錄。 這並不表示這些物件必須開放供較低完整性程式修改。 繼承的 (或預設) 檔案系統或登錄物件上由高層級或系統層級進程建立的任意存取控制清單,只會授與系統管理員群組成員或本機系統或服務帳戶的寫入權限。
使用中型預設隱含強制標籤所需的一些設計條件約束,而不是根據主體對大部分物件類型的完整性層級指派明確的強制標籤。 特定範例是以使用本機安全性原則啟用或停用使用者帳戶控制的能力為基礎。 停用 UAC 時,屬於本機 Administrators 群組成員的使用者,具有具有高完整性層級之完整許可權存取權杖執行的所有進程。 如果所有物件在主體的完整性層級明確加上標籤,則使用者建立的檔和試算表等所有檔案都會被指派高完整性層級。 雖然使用者設定檔的繼承 DACL 許可權提供足夠的存取控制,但高標籤看起來會很適合。 不過,如果本機電腦或群組原則啟用 UAC,則相同使用者執行的大部分進程都會在中完整性層級指派篩選的安全性存取權杖。 啟用 UAC 之後,使用者將無法開啟停用 UAC 時所建立的檔案。 嘗試開啟使用者高完整性檔的中完整性應用程式會收到拒絕存取錯誤。
如果進程執行時的主旨完整性層級小於預設完整性層級的中型,該進程將會限制對具有隱含中完整性層級的所有物件的存取權限。 具有低完整性層級的進程將無法修改具有中或更高明確或隱含完整性層級的任何物件,而不論 DACL 中授與給安全性主體的存取權限為何。 因此,由主體完整性層級小於預設層級的程式所建立的所有物件, (中度) 都會由安全性子系統明確標記。 Windows Vista 中可能會有低完整性程式的存取限制,因為所有應用程式通常會在中完整性層級執行,且應用程式相容性問題最少。 在低完整性上正確執行的應用程式通常需要特定設計變更,才能使用受限制的存取正確運作。 下一節將討論設計變更: 在低完整性層級設計要執行的應用程式。
標記由低主旨建立的物件
應用程式可以在低完整性層級開始使用 CreateProcessAsUser 函式。 CreateProcessAsUser 會使用下列完整性層級資訊來初始化低進程:
- 新的進程物件是使用包含低完整性之強制標籤的安全性描述項所建立。
- 系統會針對該進程建立新的執行緒物件,並使用包含低完整性之強制標籤的安全性描述元。
- 主要存取權杖會指派給新的進程。 存取權杖物件具有安全性描述項,且低度標籤為強制標籤,而存取權杖包含 TokenIntegrityLevel,且具有低完整性 SID,代表主體完整性層級。
假設低完整性進程正在執行,而且想要建立執行緒。 若要建立執行緒,它必須開啟自己的進程物件,以便寫入存取權以建立新的執行緒物件。 如果進程物件上的強制標籤為中,低主旨將無法開啟進程,而且無法建立新的執行緒。 因為進程物件也標示為低完整性,所以允許低主體開啟進程以進行寫入存取,並建立新的執行緒物件。 此範例顯示為什麼進程物件、執行緒物件和安全性存取權杖上的必要標籤在相同完整性層級上必須一致。
注意
這適用于所有完整性層級,而不只是低主體。
假設低進程會建立暫存檔案。 應用程式會呼叫 CreateFile 來建立新的檔案、寫入一些資料,然後關閉檔案。 稍後,低進程想要重新開啟相同的檔案以附加資料。 如果暫存檔在中度完整性層級具有隱含的預設強制標籤,則低進程將無法重新開啟稍早建立以供修改存取的檔案。 若主體完整性層級低於預設媒體層級所建立的任何安全性實體物件,可能會發生相同的問題。 因此,具有預設層級以下之主體所建立的所有安全性實體物件都會自動指派明確的強制標籤。 換句話說,當主體完整性層級很低時,所有核心物件、登錄機碼和檔案系統物件都會明確標示為低。
如何建立具有特定強制標籤的物件
大部分的 Windows 應用程式不需要「完整性感知」。 安全性子系統會自動建立物件,並為其指派強制標籤。 由於大部分的應用程式在中度完整性層級執行,而預設物件完整性層級為中,因此完整性原則不會變更大部分應用程式的允許存取控制。 不過,某些應用程式,例如服務,是設計來支援不同完整性層級的用戶端應用程式。 服務可能以比用戶端更高的完整性層級執行,而且可能想要標示以較低完整性層級明確代表用戶端建立的新物件。 建立程式可以設定物件的完整性層級。 條件約束是新物件上的完整性層級必須小於或等於建立程式的完整性層級。
若要建立具有特定強制標籤的物件 |
|
強制標籤繼承
Windows Vista 不會明確標記 NTFS 檔案系統中的檔案和目錄。 如先前所述,安全性子系統會針對安全性描述元中沒有強制標籤的物件,使用預設層級為中度的隱含強制標籤。
應用程式的設計目的是要以低完整性層級執行。 受保護的模式 Internet Explorer 是 Windows Vista 應用程式的範例,其設計目的是要以低完整性執行。 低完整性的應用程式可能需要檔案系統中的資料夾,才能寫入暫存檔案或應用程式資料。 如果是受保護的模式 Internet Explorer,則會使用使用者設定檔中的暫存網際網路檔案資料夾。 低應用程式如何寫入檔系統資料夾? 資料夾必須獲指派明確的強制標籤,以允許從低完整性進程進行寫入存取。
根據應用程式設計,可能會有其他一些程式可將檔案新增至低完整性應用程式所使用的資料夾。 如果其他進程也以低完整性執行,這些進程所建立的檔案會自動指派低強制標籤。 不過,如果另一個夥伴進程具有較高的完整性,則夥伴程式 (檔案同步處理服務,或使用者代理程式) 可能會在低度標籤的低資料夾中建立檔案。 合作夥伴程式會在低應用程式所使用的資料夾中建立中型檔案,低應用程式無法修改或刪除。
完整性機制可讓具有低強制標籤的資料夾具有子物件、檔案和子資料夾,每個資料夾都有不同的較高強制標籤,因為每個檔案系統物件都有唯一的安全性描述元。 有許多案例是,對於指派低強制標籤的資料夾,資料夾中的所有檔案都必須指派低強制標籤,讓低進程可以修改它們。 完整性機制可藉由讓強制標籤 ACE 從父容器繼承至子容器和子物件,以支援此功能。
必要的標籤 ACE 類型資料結構包含具有 AceFlags 欄位的 ACE 標頭。 AceFlags 欄位是用來定義 ACE 類型的繼承旗標,該類型與其他 ACE 類型的繼承旗標相同,例如用於選擇性存取的 Access Allowed ACE 類型。 您可以針對 容器繼承 (CI) 和/或 物件繼承 (OI) ,將強制標籤 ACE 定義為可繼承。 強制標籤 ACE 無法 inherit_only (IO) 。 如果有指派給容器的可繼承強制標籤 ACE,則強制標籤會套用至容器本身,以及套用繼承的子物件。
繼承強制標籤的範例是每個使用者設定檔下所建立其中一個資料夾的低強制標籤:%USERPROFILE%\AppData\LocalLow。 當設定檔初始化並預期為低完整性應用程式可寫入的最上層資料夾時,此資料夾會指派低強制標籤。 下圖顯示使用 Icacls 命令所顯示 AppData\LocalLow 資料夾上的可繼承必要標籤。 如需 Icacls 如何支援強制標籤的詳細資訊,請參閱 附錄 B:Icacls 和檔案完整性層級。
強制標籤中的繼承旗標表示 ACE (OI) ,並 (具有NO_WRITE_UP (NW) 強制原則的 ACE) ACE。 在 AppData\LocalLow 資料夾下建立的所有子資料夾都會繼承可繼承的標籤。
圖 4 可繼承的低強制標籤
從中型進程建立新檔案或子資料夾時,新物件會繼承低強制標籤。 在下列範例中,命令提示字元正以中度完整性層級執行。 檔案、newfile.txt和新資料夾 Temp 會在 LocalLow 資料夾中建立,而且這兩個物件都會從父容器繼承低強制標籤。 Icacls 表示強制標籤會繼承 (I) 指定。
圖 5 繼承子物件上的強制標籤
強制標籤的繼承可確保在檔案系統命名空間的一部分下建立之物件完整性層級的一致性。
繼承和明確標籤
在具有可繼承強制標籤的容器中建立的物件會繼承容器中的強制標籤。 不過,建立新物件的程式,例如檔案,可以在 create 函式的安全性屬性參數中提供明確的強制標籤,例如 CreateFile。
如果建立程式提供明確標籤做為物件 create 函式的參數,新物件會指派呼叫端所提供的明確強制標籤,而且不會繼承自父容器。 明確強制標籤的完整性層級不高於建立物件的主體程式。 主體所提供明確強制標籤中的完整性層級可能高於父容器可繼承的強制標籤中的完整性層級。
僅限繼承限制
僅限繼承 (IO) 是存取控制專案中的旗標,表示 ACE 不會控制其附加物件的存取權。 僅限繼承 ACE 通常會指派給容器物件。 僅限繼承的 ACE 對容器本身無效;相反地,它會套用至容器的子物件。 對於完整性層級小於預設的主體,在新物件上設定INHERIT_ONLY標籤有一項限制。 如果針對新容器物件傳入的明確標籤是INHERIT_ONLY標籤,且層級小於預設值,則標籤會被視為無效並忽略。 這項限制的原理是低主體會建立容器,並嘗試在容器上設定低INHERIT_ONLY標籤。 如果已接受INHERIT_ONLY標籤,容器的有效完整性層級會是中隱含的預設層級。
此外,主旨無法定義完整性層級高於主體完整性層級的INHERIT_ONLY標籤。 例如,中型主旨無法定義具有高完整性層級的INHERIT_ONLY標籤。
受保護的 SACL 和標籤繼承
SDDL 支援定義受保護的 SACL,其中可能包含明確的強制標籤。 受保護的 SACL 會在安全描述元的 [SECURITY_DESCRIPTOR_CONTROL] 欄位中設定SE_SACL_PROTECTED旗標。 LABEL_SECURITY_INFORMATION和SACL_SECURITY_INFORMATION與存取權限的邏輯區隔,與受保護 SACL 的行為方式並不完全。 強制標籤會儲存在 SACL 中。 受保護的 SACL 表示強制標籤也會受到保護。
如果在SECURITY_DESCRIPTOR_CONTROL中設定SE_SACL_PROTECTED旗標,則強制標籤也會受到保護。
- 如果受保護的 SACL 中沒有強制標籤 ACE,則不會套用來自容器的可繼承強制標籤 ACE, (新物件具有隱含的預設強制標籤) 。
- 如果受保護 SACL 中有強制標籤 ACE,容器上可繼承標籤 ACE 的變更不會影響此物件。
如需 SDDL 的詳細資訊,請參閱 附錄 A:強制標籤的 SDDL 或 Windows 完整性機制資源。
存取檢查如何使用強制原則
AccessCheck函式會強制執行強制原則。 AccessCheck 會比較指定的安全性描述元與指定的存取權杖,並在 AccessStatus 參數中指出是否授與或拒絕存取。 AccessCheck 函式會先比較 ClientToken 中的完整性層級與 pSecurityDescriptor SACL 中的強制標籤,以根據強制原則判斷無法使用的存取權限。 在強制原則檢查之後,AccessCheck 會比較所需的存取權與 DACL 中授與的存取權限。
預設強制原則可防止較低完整性進程取得較高完整性物件的一般寫入存取權。 例如,根據預設,低完整性進程會拒絕對具有較高完整性層級之物件的泛型寫入存取。 如果 pSecurityDescriptor 不包含強制 ACE,則會假設隱含的強制 ACE 會將物件指派為中度完整性層級。 GenericMapping參數會決定哪些存取權限與泛型寫入權限相關聯。 如果 GenericMapping 參數全部為零,則完整性檢查不會將任何特定存取權限授與較低完整性 ClientToken。 完整性檢查會根據強制原則判斷呼叫端可用的一般存取權限之後,安全性描述項的 DACL 會與 ClientToken 進行比較,以判斷剩餘的已授與存取權限。
使用者介面許可權隔離 (UIPI) 和完整性
使用者介面許可權隔離 (UIPI) 會在 Windows 子系統中實作限制,以防止較低許可權的應用程式傳送視窗訊息,或在較高許可權進程中安裝勾點。 允許較高許可權的應用程式將視窗訊息傳送至較低許可權的進程。 限制是在 SendMessage 和相關視窗訊息函式中實作。 並非所有從較低許可權進程傳送到較高許可權進程的視窗訊息都會遭到封鎖。 一般而言,「讀取」類型訊息例如 WM_GETTEXT,可以從較低許可權傳送至較高許可權視窗。 不過,會封鎖寫入類型訊息,例如WM_SETTEXT。
UI 許可權層級位於進程層級,並套用至進程所建立的所有視窗。 當使用者第一次呼叫 Windows 圖形裝置介面時,USER 子系統會初始化 (GDI) 。 在進程初始化期間,USER 子系統會呼叫 安全性子系統,以判斷在進程的主要安全性存取權杖中指派的完整性層級。 在使用者子系統在進程初始化期間設定 UI 許可權等級之後,它不會變更。 將執行緒的 TokenIntegrityLevel 設定為較低的值,不會影響進程的 UI 許可權等級,或由該進程或執行緒開啟的任何視窗。
UIPI 不會干擾或變更應用程式在相同許可權 (或完整性) 層級之間的視窗傳訊行為。 UIPI 會封鎖下列行為,防止較低許可權進程存取較高許可權的進程。 較低許可權的程式無法:
- 執行具有較高許可權之進程的視窗控制碼驗證。
- 使用 SendMessage 或 PostMessage 對具有較高許可權執行的應用程式視窗。 這些 API 會傳回成功,但會以無訊息方式卸載視窗訊息。
- 使用執行緒勾點附加至具有較高許可權執行的進程。
- 使用日誌勾點來監視以較高許可權執行的進程。
- 執行動態連結程式庫 (DLL) 插入至具有較高許可權執行的進程。
啟用 UIPI 之後,在不同許可權層級的進程之間仍會共用下列共用使用者資源。
- 實際擁有螢幕介面的桌面視窗
- 桌面堆積唯讀共用記憶體
- 全域 Atom 資料表
- 剪貼簿
繪製到畫面是 UIPI 未封鎖的另一個動作。 GDI) 模型 (USER/graphics 裝置介面不允許控制繪製表面。 因此,針對具有較高許可權執行的應用程式,執行的應用程式可能擁有較少的許可權,在應用程式視窗介面上繪製。
UI 自動化應用程式的 UIAccess
Microsoft UI 自動化是 Windows Vista 模型,可透過舊版模型的改善來支援協助工具需求,稱為 Microsoft Active Accessibility (MSAA) 。 設計來支援無障礙使用者體驗的應用程式,可代表使用者控制其他 Windows 應用程式的行為。 當所有應用程式 (自動化用戶端和伺服器) 以標準使用者身分執行時,也就是說,在中完整性層級,UIPI 限制不會干擾 UI 自動化模型。
不過,有時候系統管理使用者會根據管理員核准模式中的 UAC,以較高的權限來執行應用程式。 使用者介面自動化程式將無法驅動桌面上提升許可權之應用程式的圖形 UI,而無法略過 UIPI 所實作的限制。 跨許可權等級略過 SendMessage 的 UIPI 限制功能,適用于使用程式應用程式資訊清單中特殊安全性屬性的 UI 自動化程式,稱為 UIAccess。
以下是 UIAccess 程式的應用程式資訊清單專案範例。
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel
level="asInvoker"
UIAccess="true" />
</requestedPrivileges>
</security>
</trustInfo>
藉由在 requestedPrivileges 屬性中指定 UIAccess=「true」 ,應用程式會指出略過跨許可權等級傳送視窗訊息的 UIPI 限制。 Windows Vista 會先實作下列原則檢查,再啟動具有 UIAccess 許可權的應用程式。
- 應用程式必須具有數位簽章,才能使用數位憑證來驗證,該數位憑證鏈結至本機電腦受信任根憑證授權單位憑證存放區中的受根信任目錄。
- 應用程式必須安裝在只有系統管理員可寫入的本機資料夾應用程式目錄中,例如 Program Files 目錄。 使用者介面自動化應用程式的允許目錄是:
- %ProgramFiles% 和其子目錄。
- %WinDir% 和其子目錄,但因標準使用者具有寫入權而排除的一些子目錄除外。
排除子目錄的 %WinDir% 子目錄包括:
- \調試
- \PCHealth
- \註冊
- \System32\ccm
- \System32\com
- \System32\FxsTmp
- \System32\Spool
- \System32\Tasks
Windows Vista 提供本機電腦原則和群組原則的安全性設定,以調整必須從安全位置啟動 UIAccess 程式的需求。 此設定定義在 [本機安全性原則] 的 [本機原則] 底下的 [安全性選項]。 安全性原則如下:
使用者帳戶控制: 僅針對在安全位置安裝的 UIAccess 應用程式,提高其權限
此設定預設為啟用狀態。 不過,如果在某些情況下,UIAccess 應用程式 (可存取技術) 必須從資料夾啟動,但不受系統管理員專用寫入存取權保護,系統管理員可以加以停用。
如果要求 UIAccess 的 UI 自動化應用程式符合 UIAccess 設定需求,則 Windows Vista 會啟動應用程式,並能夠略過大部分的 UIPI 限制。 如果 UI 自動化應用程式不符合安全性限制,則會在沒有 UIAccess 許可權的情況下啟動應用程式,而且只能與相同或較低許可權等級的應用程式互動。
使用 UIAccess 許可權啟動的進程:
- 能夠設定前景視窗。
- 可以使用 SendInput 函式驅動任何應用程式視窗。
- 具有使用低階勾點、原始輸入、GetKeyState、GetAsyncKeyState 和 GetKeyboardInput 之所有完整性層級的讀取輸入。
- 可以設定日誌勾點。
- 使用 AttachThreadInput 將執行緒附加至較高的完整性輸入佇列
使用標準使用者 UIAccess 許可權啟動的應用程式,會在存取權杖中指派稍微較高的完整性層級值。 標準使用者的 UIAccess 應用程式的存取權杖完整性層級是中度完整性層級的值,加上0x10遞增。 UIAccess 應用程式更高的完整性層級可防止在中度完整性層級的相同桌面上開啟 UIAccess 進程物件。