適用於驅動程式開發人員的 Windows 安全性模型
Windows 安全性模型是以安全性實體對象為基礎。 操作系統的每個元件都必須確保其負責的物件安全性。 因此,驅動程式必須保護其裝置和裝置對象的安全性。
本主題摘要說明 Windows 安全性模型如何套用至內核模式驅動程式。
Windows 安全性模型
Windows 安全性模型主要以個別物件許可權為基礎,具有少量的系統範圍許可權。 可以保護的物件包括,但不限於進程、線程、事件和其他同步處理物件,以及檔案、目錄和裝置。
針對每種物件類型,通用的讀取、寫入和執行權限會對應到詳細的物件專屬權限。 例如,對於檔案和目錄,可能的許可權包括讀取或寫入檔案或目錄、讀取或寫入擴充檔案屬性的許可權、周遊目錄的許可權,以及寫入物件的安全性描述元的許可權。
安全性模型包含下列概念:
- 安全性識別碼 (SID)
- 存取令牌
- 安全性描述元
- 存取控制清單 (ACL)
- 特權
安全性識別碼 (SID)
安全性標識碼 (SID,也稱為 主體)會識別使用者、群組或登入會話。 每個使用者都有唯一的 SID,這是操作系統在登入時擷取的。
SID 是由作業系統或網域伺服器等授權單位所發出。 某些 SID 是已知的,而且具有名稱和識別碼。 例如,SID S-1-1-0 會識別所有人(或全球)。
存取令牌
每個進程都有存取令牌。 存取令牌描述程式的完整安全性內容。 其中包含使用者的 SID、使用者所屬群組的 SID、登入工作階段的 SID,以及授與使用者的全系統許可權清單。
根據預設,每當進程線程與安全性實體對象互動時,系統就會使用進程的主要存取令牌。 不過,線程可以模擬客戶端帳戶。 當線程模擬時,除了它自己的主要令牌之外,還有模擬令牌。 模擬令牌表示線程模擬的用戶帳戶的安全性上下文。 冒充在遠端過程調用(RPC)處理中特別常見。
描述線程或進程的受限制安全性內容的存取令牌稱為受限制的令牌。 限制令牌中的 SID 只能設為拒絕存取,而非允許存取可安全管理的物件。 此外,令牌可以描述一組有限的全系統許可權。 使用者的 SID 和身分識別保持不變,但在進程使用受限制的令牌時,使用者的存取權限會受到限制。 CreateRestrictedToken 函式會建立受限制的令牌。
安全性描述元
每個具名 Windows 物件都有安全性描述元;某些未命名的物件也會這麼做。 安全性描述項說明物件的擁有者和群組 SID 及其 ACL。
對象的安全性描述元通常是由建立物件的函式所建立。 當驅動程式呼叫 IoCreateDevice 或 IoCreateDeviceSecure 例程來建立裝置物件時,系統會將安全性描述元套用至建立的裝置物件,並設定物件的 ACL。 針對大部分的裝置,ACL 會在裝置資訊 (INF) 檔案中指定。
如需核心驅動程式檔中 安全性描述元 的詳細資訊。
訪問控制清單
訪問控制清單 (ACL) 可對物件的存取進行更細緻的控制。 ACL 是每個物件之安全性描述元的一部分。
每個 ACL 都包含零個或多個存取控制項目(ACE)。 接著,每個 ACE 都包含單一 SID,可識別使用者、群組或計算機,以及該 SID 遭到拒絕或允許的許可權清單。
裝置物件的 ACL
裝置物件的 ACL 可以用下列三種方式之一來設定:
- 在其裝置類型的預設安全性描述元中設定。
- 由 RtlCreateSecurityDescriptor 函式以程序設計方式建立,並由 RtlSetDaclSecurityDescriptor 函式設定。
- 在裝置的 INF 檔案中或呼叫 IoCreateDeviceSecure 例程時指定的安全性描述元定義語言 (SDDL)。
所有驅動程式都應該使用 INF 檔案中的 SDDL 來指定其裝置物件的 ACL。
SDDL 是可延伸的描述語言,可讓元件以字串格式建立 ACL。 使用者模式和內核模式程序代碼都使用 SDDL。 下圖顯示裝置物件的SDDL字串格式。
Access 值會指定允許的存取類型。 SID 值會指定安全性識別碼,以決定 Access 值套用的物件(例如,使用者或群組)。
例如,下列 SDDL 字串允許系統 (SY) 存取所有內容,並允許所有其他人 (WD) 僅限讀取:
“D:P(A;;GA;;;SY)(A;;GR;;;WD)”
頭檔 wdmsec.h 也包含一組適用於裝置物件的預先定義 SDDL 字串。 例如,標頭檔案會定義 SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RWX_RES_RWX,如下所示:
"D:P(A;;GA;;;SY)(A;;GRGWGX;;;BA)(A;;GRGWGX;;;WD)(A;;GRGWGX;;;RC)"
此字串的第一個區段可讓核心和作業系統 (SY) 完全控制裝置。 第二個區段可讓內建 Administrators 群組 (BA) 中的任何人存取整個裝置,但不允許變更 ACL。 第三個區段允許所有人(WD)讀取或寫入裝置,第四個區段則將相同的權限授予不受信任的程式碼(RC)。 驅動程式可以直接使用預定義的字串,或將其作為裝置物件特定字串的範本。
堆疊中的所有裝置物件都應該具有相同的 ACL。 變更堆疊中一個裝置物件上的 ACL 會變更整個裝置堆疊上的 ACL。
不過,將新的裝置物件新增至堆疊並不會改變任何 ACL,無論是新裝置物件的 ACL(如果有的話),還是堆疊中任何現有裝置物件的 ACL。 當驅動程式建立新的裝置物件並將它附加至堆疊頂端時,驅動程式應該從下一個較低的驅動程式複製 DeviceObject.Characteristics 字段,將堆棧的 ACL 複製到新的裝置物件。
IoCreateDeviceSecure 例程支援使用包含預定義 SID(如 WD 和 SY)之 SDDL 字串子集。 使用者模式 API 和 INF 檔案支援完整的 SDDL 語法。
使用 ACL 進行安全檢查
當進程要求存取物件時,安全性檢查會將物件的 ACL 與呼叫端存取令牌中的 SID 進行比較。
系統會以嚴格的由上至下的順序比較 ACEs,並在第一個相關匹配點停止。 因此,建立 ACL 時,您應該一律將拒絕 ACE 置於對應的授與 ACE 之上。 下列範例顯示比較的過程。
範例 1:比較 ACL 與存取令牌
範例 1 顯示系統如何比較 ACL 與呼叫端進程的存取令牌。 假設呼叫端想要開啟具有下表所示 ACL 的檔案。
範例檔案 ACL
許可 | SID | 存取 |
---|---|---|
允許 | 會計學 | 寫入、刪除 |
允許 | 銷售 | 添加 |
否認 | 法律 | 附加、寫入、刪除 |
允許 | 每個人 都 | 讀 |
此 ACL 有四個 ACE,特別適用於會計、銷售、法律及所有人群組。
接下來,假設要求程式的存取令牌包含一個使用者和三個群組的 SID,順序如下:
使用者吉姆 (S-1-5-21...)
集團會計(S-1-5-22...)
群組法律 (S-1-5-23...)
群組所有人(S-1-1-0)
比較檔案 ACL 與存取令牌時,系統會先在檔案的 ACL 中尋找使用者 Jim 的 ACE。 沒有找到,因此接下來會尋找會計群組的 ACE。 如上表所示,會計群組的 ACE 被列為檔案 ACL 中的第一個項目,因此 Jim 的程序被授予寫入或刪除檔案的權限,並且比較過程隨之終止。 如果法律群組的 ACE 位於 ACL 中會計群組的 ACE 之前,則程序將被拒絕寫入、附加和刪除檔案的存取權。
範例 2:比較 ACL 與受限制的令牌
系統會比較 ACL 與受限制令牌的方式,與比較未受限制之令牌中的令牌相同。 不過,受限制的令牌中的拒絕 SID 只能匹配 ACL 中的拒絕 ACE。
範例 2 顯示系統如何比較檔案的 ACL 與受限制的令牌。 假設檔案與上表所示的 ACL 相同。 不過,在此範例中,進程具有包含下列 SID 的受限制令牌:
使用者吉姆 (S-1-5-21...)否認
組會計 (S-1-5-22...)否認
群組法律 (S-1-5-23...)否認
群組所有人(S-1-1-0)
檔案的 ACL 中未列出 Jim 的 SID,因此系統會接著檢查會計群組的 SID。 檔案的 ACL 雖然包含會計群組的 ACE,但此 ACE 允許存取,因此並不匹配進程受限制令牌中的 SID,從而拒絕存取。 因此,系統會繼續進行法律群組 SID。 檔案的 ACL 包含法律群組拒絕存取的 ACE,因此進程無法寫入、附加或刪除檔案。
特權
許可權可讓使用者在本機計算機上執行系統相關作業,例如載入驅動程式、變更時間或關閉系統。
許可權與訪問許可權不同,因為它們會套用至系統相關的工作和資源,而不是物件,而且因為許可權是由系統管理員指派給使用者或群組,而不是由操作系統指派。
每個進程的存取令牌都包含授與給進程的許可權清單。 使用之前,必須特別啟用許可權。 如需許可權的詳細資訊,請參閱核心驅動程序檔中的 Privileges。
安全性相關調試程式命令
!acl 延伸模組會格式化並顯示訪問控制清單的內容(ACL)。 如需詳細資訊,請參閱 判斷物件 的 ACL 和 !acl。
!token 延伸模組會顯示安全性令牌物件的格式化檢視。 如需詳細資訊,請參閱 !token。
!tokenfields 延伸模組會顯示存取令牌物件中欄位的名稱和位移(TOKEN 結構)。 如需詳細資訊,請參閱 !tokenfields。
!sid 延伸模組會顯示位於指定位址的安全性識別碼 (SID)。 如需詳細資訊,請參閱 !sid。
!sd 延伸模組會顯示指定位址的安全性描述元。 如需詳細資訊,請參閱 !sd。
Windows 安全性模型案例:建立檔案
每當程序生成檔案或物件的控制代碼時,系統會使用 Windows 安全性模型中描述的安全性機制。
下圖顯示當使用者模式進程嘗試建立檔案時所觸發的安全性相關動作。
上圖顯示當使用者模式應用程式呼叫 createFile 函式時,系統如何回應。 下列附註指的是圖中的圓圈數位:
- 使用者模式應用程式會呼叫 CreateFile 函式,並傳遞有效的 Microsoft Win32 檔名。
- 使用者模式 Kernel32.dll 會將要求傳遞至 Ntdll.dll,此要求會將 Win32 名稱轉換成Microsoft Windows NT 檔名。
- Ntdll.dll 使用 Windows 檔名呼叫 NtCreateFile 函式。 在 Ntoskrnl.exe內,I/O 管理員會處理 NtCreateFile。
- I/O 管理員會將要求重新封裝到物件管理員呼叫中。
- 物件管理員會解析符號連結,並確保使用者具有檔案建立路徑的周遊許可權。 如需詳細資訊,請參閱物件管理員中
安全性檢查。 - 物件管理員會呼叫系統元件,該元件擁有與要求相關聯的基礎物件類型。 對於檔案建立要求,此元件是擁有裝置物件的 I/O 管理員。
- I/O 管理員會根據使用者的存取令牌檢查裝置對象的安全性描述元,以確保使用者具有裝置的必要存取權。 如需詳細資訊,請參閱 I/O 管理員中
安全性檢查。 - 如果使用者進程具有必要的存取權限,I/O 管理員會建立句柄,並將 IRP_MJ_CREATE 要求傳送給裝置或文件系統的驅動程式。
- 驅動程式會視需要執行其他安全性檢查。 例如,如果要求指定裝置命名空間中的物件,驅動程式必須確定呼叫端具有必要的訪問許可權。 如需詳細資訊,請參閱驅動程式中
安全性檢查。
物件管理員中的安全性檢查
檢查存取權限的責任屬於可執行這類檢查的最上層元件。 如果物件管理員可以驗證呼叫者的訪問許可權,則會這麼做。 如果沒有,物件管理員會將要求傳遞給負責基礎物件類型的元件。 如果可以,該元件接著會驗證存取權;如果無法,它會將要求傳遞至仍然較低的元件,例如驅動程式。
物件管理員會檢查 ACL 是否有簡單的物件類型,例如事件和 Mutex 鎖定。 對於具有命名空間的物件,類型擁有者會執行安全性檢查。 例如,I/O 管理員會被視為裝置對象和檔案對象的類型擁有者。 如果物件管理員在剖析名稱時找到裝置物件或檔案對象的名稱,則會將名稱交給 I/O 管理員,如上述檔案建立案例所示。 I/O 管理員接著會檢查存取權限,如果可能的話。 如果名稱指定裝置命名空間中的物件,I/O 管理員會將名稱轉交給裝置或檔案系統驅動程式,而該驅動程式負責驗證所請求的存取權限。
I/O 管理員中的安全性檢查
當 I/O 管理員建立句柄時,它會根據進程存取令牌檢查對象的許可權,然後將授與給使用者的許可權連同句柄一起儲存。 當稍後的 I/O 要求到達時,I/O 管理員會檢查與控制代碼相關聯的許可權,以確保程序有權執行所請求的 I/O 操作。 例如,如果程序稍後要求執行寫入操作,I/O 管理器會檢查與控制代碼相關聯的權限,以確保呼叫者擁有對該物件的寫入權限。
當句柄重複時,可以從複本中移除權限,但無法向其新增權限。
當 I/O 管理員建立物件時,它會將一般 Win32 存取模式轉換為物件特定的許可權。 例如,下列許可權適用於檔案和目錄:
Win32 存取模式 | 物件特定權利 |
---|---|
一般讀取權限 | 資料讀取 |
通用寫入 (GENERIC_WRITE) | WriteData |
通用執行權限 | ReadAttributes |
通用_全部 | 都 |
若要建立檔案,進程必須具有目標路徑中父目錄的周遊許可權。 例如,若要建立 \Device\CDROM0\Directory\File.txt,程序必須擁有權限存取 \Device、\Device\CDROM0 和 \Device\CDROM0\Directory。 I/O 管理員只會檢查這些目錄的存取權限。
I/O 管理員在剖析檔名時會檢查遍歷許可權。 如果檔名是符號連結,I/O 管理員會將其解析為完整路徑,然後從根目錄開始檢查遍歷權限。 例如,假設符號連結 \DosDevices\D 對應至 Windows NT 裝置名稱 \Device\CDROM0。 程序必須具有 \Device 目錄的遍歷權限。
驅動程式中的安全性檢查
操作系統核心會將每個驅動程式視為具有其本身命名空間的文件系統。 因此,當呼叫端嘗試在裝置命名空間中建立物件時,I/O 管理員會檢查進程是否具有路徑中目錄的周遊許可權。
使用 WDM 驅動程式時,除非已建立指定FILE_DEVICE_SECURE_OPEN的 Device Object,否則 I/O 管理員不會對命名空間執行安全性檢查。 未設定FILE_DEVICE_SECURE_OPEN時,驅動程式會負責確保其命名空間的安全性。 如需詳細資訊,請參閱 控制裝置命名空間存取 和 保護裝置物件。
針對WDF驅動程式,一律會設定FILE_DEVICE_SECURE_OPEN旗標,以便在允許應用程式存取裝置命名空間內的任何名稱之前,先檢查裝置的安全性描述項。 如需詳細資訊,請參閱KMDF 驅動程式中
Windows 安全性界限
驅動程式之間,以及與擁有不同權限等級的使用者模式呼叫者之間的通訊,被視為穿越信任邊界。 信任界限是任何從較低許可權進程進入較高特殊許可權進程的程式代碼執行路徑。
當許可權等級的差距越大,界限對於想要對目標驅動程式或進程執行攻擊(如許可權提升攻擊)的攻擊者而言就越有吸引力。
建立威脅模型的一部分是檢查安全性界限,並尋找未預期的路徑。 如需詳細資訊,請參閱驅動程式
跨越信任界限的任何數據都是不受信任的,而且必須經過驗證。
此圖顯示三個核心驅動程式,以及兩個應用程式,一個在應用程式容器中,另一個是使用系統管理員許可權執行的應用程式。 紅線表示範例信任界限。
由於應用程式容器可以提供額外的條件約束,而且未在系統管理層級執行,因為信任界限位於應用程式容器(非常低許可權進程)和核心驅動程式之間,因此路徑 (1) 是提升攻擊的風險較高。
路徑 (2) 是風險較低的路徑,因為應用程式是以系統管理員許可權執行,並直接呼叫核心驅動程式。 系統管理員在系統上已經擁有相當高的權限,因此從系統管理員到核心的攻擊面對於攻擊者來說相對不那麼有吸引力,但仍然是一個值得注意的信任界限。
Path (3) 是程式代碼執行路徑的範例,其跨越多個信任界限,如果未建立威脅模型,可能會遺漏這些界限。 在此範例中,驅動程式 1 與驅動程式 3 之間有信任界限,因為驅動程式 1 會從使用者模式應用程式取得輸入,並將它直接傳遞至驅動程式 3。
從使用者模式進入驅動程式的所有輸入都是不受信任的,而且應該經過驗證。 來自其他驅動程式的輸入也可能不受信任,取決於先前的驅動程式是否只是簡單的傳遞(例如驅動程式 1 從應用程式 1 收到數據,驅動程式 1 未對數據進行任何驗證,而只是將它轉送至驅動程式 3)。 請務必藉由建立完整的威脅模型,識別所有受攻擊面和信任界限,並驗證跨越它們的所有數據。
Windows 安全性模型建議
- 在呼叫 IoCreateDeviceSecure 例程中設定強式預設 ACL。
- 為每個裝置在 INF 檔案中指定 ACL。 這些 ACL 可以在必要時放寬緊密的預設 ACL。
- 設定FILE_DEVICE_SECURE_OPEN特性,將裝置物件安全性設定套用至裝置命名空間。
- 請勿定義允許FILE_ANY_ACCESS的 IOCTL,除非無法惡意利用這類存取。
- 使用 IoValidateDeviceIoControlAccess 例程來強化允許FILE_ANY_ACCESS的現有 IOCTLS 安全性。
- 建立威脅模型來檢查安全性界限,並尋找未預期的路徑。 如需詳細資訊,請參閱驅動程式 威脅建模。
- 如需其他驅動程式安全性建議,請參閱 驅動程式安全性檢查清單。