《windows核心編程》筆記(三)——第三章:內核對象:安全描述符SECURITY_DESCRIPTOR


安全對象Securable Object

  安全對象Securable Object是擁有SD的Windows的對象。

  所有的被命名的Windows的對象都是安全對象。一些沒有命名的對象是安全對象,如:進程和線程,也有安全描述符SD。安全對象Securable Object是擁有SD的Windows的對象。
  在 Windows系統中,其是用一個安全描述符(Security Descriptors)的結構來保存其權限的設置信息,簡稱為SD,其在Windows SDK中的結構名是“SECURITY_DESCRIPTOR”,這是包括了安全設置信息的結構體。一個安全描述符包含以下信息:

  • 一個安全標識符(Security identifiers),其標識了該信息是哪個對象的,也就是用於記錄安全對象的ID。簡稱為:SID。
  • 一個DACL(Discretionary Access Control List),其指出了允許和拒絕某用戶或用戶組的存取控制列表。 當一個進程需要訪問安全對象,系統就會檢查DACL來決定進程的訪問權。如果一個對象沒有DACL,那么就是說這個對象是任何人都可以擁有完全的訪問權 限。
  • 一個SACL(System Access Control List),其指出了在該對象上的一組存取方式(如,讀、寫、運行等)的存取控制權限細節的列表。
  • 還有其自身的一些控制位。

  DACL和SACL構成了整個存取控制列表Access Control List,簡稱ACL,ACL中的每一項,我們叫做ACE(Access Control Entry)

訪問控制鏈表(ACL)

  一個 ACL 是一個 ACE 鏈表。每個 ACL 中的 ACE 標示一個托管以及指定允許的訪問權限、否定或托管的設計。一個對象的安全描述符號包含兩種類型的 ACL ,一個是 DACL ,一個是 SACL 。
  一個目錄訪問控制鏈表( DACL )標示允許或拒絕訪問一個安全對象的托管。當一個進程常識訪問一個安全對象的時候,系統檢查對象的 DACL 中的 ACE 來決定是否賦予訪問權限。如果對象沒有 DACL ,系統賦予完全的訪問權限,如果對象的 DACL 沒有 ACE ,那么系統拒絕所有訪問對象的嘗試,因為 DACL 不允許任何訪問權限。系統檢查 ACE 序列直到找到一到多個 ACE ,或者直到任何請求的訪問權限被否定。更多的信息參見: DACL 怎么樣控制一個對象的。對於創建 DACL 的信息,見創建一個 DACL
  一個系統訪問控制鏈表( SACL )是管理員登錄嘗試訪問一個安全對象。每個 ACE 指定一個指定的托管嘗試的訪問類型,這個訪問會導致系統產生一個安全事件日志。一個 SACL 中的 ACE 能夠產生訪問嘗試失敗或成功的時候產生評估記錄,在將來的 release 中,一個 SACL 在一個未授權用戶嘗試訪問一個對象的時候發出一個警告。更多 SACL 的信息參見 Audit Generation 和 SACL 訪問權限
  不要嘗試直接使用一個 ACL 來工作。為了確保 ACL 能夠語義正確的,使用適當的函數來創建和操縱 ACL 。更多的信息參見:從 ACL 中取得信息和創建或修改一個 ACL
ACL 也提供訪問控制微軟的 Active Directory 目錄服務對象。活動目錄服務接口( ADSI )包括創建和修改 ACL 內容的程序。更多信息參見:控制訪問活動目錄對象

訪問控制實體(ACE)

  一個訪問控制實體(ACE)是ACL中的一個元素。一個ACL可能包含0到多個ACE。每個ACE通過一個指定的托管來控制或監視一個對象。更多關於添加、刪除、改變ACE,見修改ACL對象。
  Window Me/98/95:不支持訪問控制
  有6種類型的ACE,三種被所有的安全對象支持,其他類型是對象特定的ACE,由目錄服務對象支持。
  所有ACE類型都包含下面訪問控制信息:

  • 一個安全標示符號(SID)來標示ACE應用的托管
  • 一個訪問掩碼指定ACE控制的訪問權限
  • 一個指示ACE類型的標志位
  • 一系列位標志決定是否子容器或對象可以繼承ACE從基本對象到ACL附着的對象。

  下表列出了三個所有安全對象支持的ACE類型:

 

Type

Description

訪問拒絕ACE

用在一個DACL中拒絕到一個托管的訪問權限

訪問允許ACE

用在一個DACL中允許到托管的訪問權限

系統評估ACE

用在SACL中,當托管嘗試檢查指定訪問權限時產生一個評估記錄

  對於對象指定的ACE,參見對象指定ACE

  注意,系統警告ACE對象現在不支持。

托管

  一個托管是一個用戶帳戶、組帳戶或登錄會話到一個ACE應用。每個ACL中的ACE都有一個SID來標示托管。用戶帳戶包含人使用的帳戶或程序帳戶(例如,Window服務用來登錄到本地計算機的)。組帳戶不能用來登錄到計算機,但在ACE中非常有用,用來拒絕或允許一到多個用戶帳戶的訪問權限。一個登錄SID表示當前的登錄會話用來允許和拒絕訪問權限,直到用戶登出。
  NT4.0和后來版本中訪問控制函數使用TRUSTEE結構體來表示一個托管。這個結構體能使你用一個字符串或一個SID來表示一個托管。如果你使用一個名字,從TRUSTEE結構創建ACE的函數執行SID緩沖區分配工作並且查詢SID對應的帳戶名稱。有兩個助手函數,BuildTrusteeWithSid和BuildTrusteeWithName,可以用SID或名字來初始化一個TRUSTEE結構。BuildTrusteeWithObjectsAndSid和BuildTrusteeWithObjectsAndName允許你使用一個對象指定的ACE信息來初始化一個TRUSTEE結構體。其他3個助手函數,GetTrusteeFrorm、GetTrusteeName和GetTrusteeType,返回TRUSTEE結構各成員的值。
  Window XP/2000:TRUSTEE的ptstrName成員可以是一個指向OBJECTS_AND_NAME或OBJECTS_AND_SID結構體的指針。這些結構體說明對象指定ACE的信息,除了托管的名字和SID之外。這可以象SetEntriesInAcl和GetExplicitEntriesFromAcl這樣的函數存儲對象指定ACE的信息到EXPLICIT_ACCESS結構體的Trustee成員中。

// TRUSTEE結構體:
typedef struct _TRUSTEE {
  PTRUSTEE pMultipleTrustee;
  MULTIPLE_TRUSTEE_OPERATION MultipleTrusteeOperation;
  TRUSTEE_FORM TrusteeForm;
  TRUSTEE_TYPE TrusteeType;
  LPTSTR ptstrName;
} TRUSTEE, *PTRUSTEE;
View Code

 

訪問權限和訪問掩碼

  一個訪問權限是一個標志位對應到一個特殊操作集合,這個集合表示線程可以在安全對象上執行的操作。例如:注冊表鍵KEY_SET_VALUE訪問權限,對應到線程在這個鍵下設置的值的能力。如果線程想在一個對象執行一個操作,但沒有必要的訪問權限,系統不執行操作。
  一個訪問掩碼是一個32位的值,它對應到對象支持的訪問權限。所有的Windows NT/2000/XP 安全對象使用一個Windows訪問掩碼格式,這個格式包含下面的訪問權限位:

  • 通用訪問權限
  • 標准訪問權限
  • SACL訪問權限
  • 目錄服務訪問權限

  當一個線程想打開一個對象的句柄,線程通常指定一個訪問掩碼來請求一系列的訪問權限。例如,需要設置和查詢注冊表鍵的程序可以使用一個訪問掩碼來請求KEY_SET_VALUE和KEY_QUERY_VALUE訪問權限來打開該鍵。

  下面表顯示了操作每種類型安全對象的信息:

對象類型

安全描述符號函數

NTFS上的文件或目錄系統

GetNamedSecurityInfo, SetNamedSecurityInfo, GetSecurityInfo, SetSecurityInfo

命名管道和匿名管道

GetSecurityInfo, SetSecurityInfo

控制台屏幕緩沖區

Not supported.

進程和線程

GetSecurityInfo, SetSecurityInfo

文件映射對象

GetNamedSecurityInfo, SetNamedSecurityInfo, GetSecurityInfo, SetSecurityInfo

Access tokens

SetKernelObjectSecurity, GetKernelObjectSecurity

Windows管理對象 (windows工作站和桌面)

GetSecurityInfo, SetSecurityInfo

注冊表鍵

GetNamedSecurityInfo, SetNamedSecurityInfo, GetSecurityInfo, SetSecurityInfo

Windows服務

GetNamedSecurityInfo, SetNamedSecurityInfo, GetSecurityInfo, SetSecurityInfo

本地和遠程打印機

GetNamedSecurityInfo, SetNamedSecurityInfo, GetSecurityInfo, SetSecurityInfo

網絡共享

GetNamedSecurityInfo, SetNamedSecurityInfo, GetSecurityInfo, SetSecurityInfo

進程間同步對象 (事件, mutexes, semaphores, and waitable timers)

GetNamedSecurityInfo, SetNamedSecurityInfo, GetSecurityInfo, SetSecurityInfo

作業對象

GetNamedSecurityInfo, SetNamedSecurityInfo, GetSecurityInfo, SetSecurityInfo

通用訪問權限

  安全對象使用Windows 訪問掩碼格式,四個高位說明通用訪問權限。每個安全對象類型映射到這些位到一系列標准和對象特殊訪問權限。例如:一個Window文件對象映射GENERIC_READ位到READ_CONTROL和SYNCHRONIZE 標准訪問權限和FILE_READ_DATA、FILE_READ_EA和FILE_READ_ATTRIBUTES對象指定訪問權限。其他類型對象映射GENERIC_READ位到與類型對象適應的一些訪問權限。
  你可以在你打開一個對象句柄的時候使用通用訪問權限來指定需要的訪問類型;這通常比指定所有對應標准和特指權限要簡單。 

  下表顯示了通用訪問權限定義的常量。

常量

解釋

GENERIC_ALL

讀、寫和執行訪問

GENERIC_EXECUTE

執行

GENERIC_READ

GENERIC_WRITE

  應用程序定義的私有安全訪問對象能使用通用訪問權限。

安全描述符(SD)

  安全描述符包含了安全對象相關的安全信息。安全描述父由一個SECURITY_DESCRIPTOR結構體組成,它關聯到一個安全對象。一個安全描述符包含下面的安全信息:

      擁有者或基本組對象的安全ID(SIDs)DACL指定特殊用戶或組的允許或拒絕的訪問權限SACL指定對象通用評估記錄嘗試的訪問類型一個控制位集合,說明安全描述符的含義或它每個成員

  程序不需要直接操作安全描述符的內容。Windows API提供設置和返回安全描述符號的函數。另外,有用來創建和初始化一個新對象安全描述符號的函數。
  Windows NT 3.51和更早的版本,Windows ME/98/95:參見:低級訪問控制。
  工作在活動目錄對象上安全描述符程序能使用Windows的安全函數或ADSI(活動目錄服務接口)提供的安全接口。更多ADSI的信息參見:訪問控制如何在活動目錄中工作?

 

DACL是怎么控制訪問對象的?

  當一個線程想訪問一個安全對象時候,系統要么允許訪問,要拒絕訪問。如果對象沒有DACL,系統賦予訪問權限,否則系統查找DACL中的該線程的ACE。每個對象DACL中的ACE指定托管的訪問允許或拒絕的訪問權限,它可以是一個用戶帳戶、組帳戶或登錄會話。
  系統比較ACE中的托管和線程訪問標記的托管標示。一個訪問標記包含SID來說明用戶和用戶輸入的組帳戶。一個標記也包含一個登錄SID,來表示當前的登錄會話。在訪問檢查期間,系統忽略不可用的組SID。更多可用不可用信息以及拒絕SID,見訪問標記中的SID屬性。
  通常,系統使用現成的基本訪問標記來請求訪問。然而,如果現成正在扮演其他用戶,系統使用現成的扮演標記。
  系統現成序列中的每個ACE,直到下面的情況發生:

  • 一個顯式拒絕任何與線程訪問標記中列出托管不同的訪問ACE出現
  • 線程訪問標記中列出的一個或多個允許訪問的ACE出現,這個標記顯式賦予所有權限。
  • 所有的ACE都檢查過,並且至少一個訪問權限沒有顯式的允許,這種情況下暗示拒絕。

  下圖描述一個DACL對象允許訪問一個線程而拒絕訪問另一個線程。

  對於線程A,系統讀ACE1並且立即拒絕訪問,因為訪問拒絕ACE應用到線程訪問標記中的用戶。這種情況下,系統並沒有檢查ACE2和3。對於線程B,ACE1沒有應用,因此系統處理ACE2,其允許寫操作,並且ACE3允許讀和執行操作。
  因為系統在請求訪問並顯式允許或拒絕的時候停止檢查,DACL中的ACE順序非常重要。注意,如果ACE順序與例子中的不同,系統可能分配訪問權限給A。對於系統對象,操作系統定義一個首選的DACL中ACE的順序。

創建一個DACL

  創建適當的 DACL 是你程序開發中必要和重要的,因為一個 NULL DACL 允許所有用戶所有訪問權限,不要使用 NULL DACL 。
  下面例子演示了如何正常創建一個 DACL 。例子,包含一個函數, CreateMyDACL ,用安全描述符定義語言( SDDL )來定義那些賦予的和拒絕的 DACL 中的訪問控制。為了提供對你程序對象的不同訪問,根據你的需要來修改 CreateMyDACL 。

  在例子中:

  1. main 函數傳遞一個 SECURITY_ATTRIBUTES 結構體的地址給 CreateMyDACL 函數
  2. CreateMyDACL 函數使用 SDDL 字符串來:
    拒絕 guest 和匿名登錄用戶訪問
    允許授權用戶的讀 / 寫 / 執行訪問
    允許管理員所有控制
  3. 更多的 SDDL 字符串格式
  4. CreateMyDACL 函數調用 ConvertStringSecurityDescriptorToSecurityDescriptor 函數轉換 SDDL 字符串為一個安全描述符。安全描述符號通過 SECURITY_ATTRIBUTES 結構體的 lpSecurityDescriptor 成員來指定。 CreateMyDACL 發送 ConvertStringSecurityDescriptorToSecurityDescriptor 的返回值給 main 函數。
  5. main 函數完成使用 SECURITY_ATTRIBUTES 結構體時, main 函數釋放 lpSecurityDescriptor 成員的內存,調用 LocalFree 函數來完成。

  注意,成功編譯 SDDL 函數,例如: ConvertStringSecurityDescriptorToSecurityDescriptor, 你必須定義 _WIN32_WINNT 常量為 0x0500 或更大。 SDDL 在 Windows 2003 家族 ,Windows XP 和 2000 操作系統上可用。

#define _WIN32_WINNT 0x0500
#include <windows.h>
#include <sddl.h>
#include <stdio.h>

BOOL CreateMyDACL(SECURITY_ATTRIBUTES *);

void main()
{
     SECURITY_ATTRIBUTES  sa;
     sa.nLength = sizeof(SECURITY_ATTRIBUTES);
     sa.bInheritHandle = FALSE;  
     // Call function to set the DACL. The DACL
     // is set in the SECURITY_ATTRIBUTES 
     // lpSecurityDescriptor member.
     if (!CreateMyDACL(&sa))
     {
         // Error encountered; generate message and exit.
         printf("Failed CreateMyDACL\n");
         exit(1);
     }

     // Use the updated SECURITY_ATTRIBUTES to specify
     // security attributes for securable objects.
     // This example uses security attributes during
     // creation of a new directory.
     if (0 == CreateDirectory(TEXT("C:\\MyFolder"), &sa))
     {
         // Error encountered; generate message and exit.
         printf("Failed CreateDirectory\n");
        exit(1);
     }

     // Free the memory allocated for the SECURITY_DESCRIPTOR.
     if (NULL != LocalFree(sa.lpSecurityDescriptor))
     {
         // Error encountered; generate message and exit.
         printf("Failed LocalFree\n");
         exit(1);
     }
}


// CreateMyDACL.
//    Create a security descriptor that contains the DACL you want.
//    This function uses SDDL to make Deny and Allow ACEs.
//
// Parameter:
//    SECURITY_ATTRIBUTES * pSA
//    Pointer to a SECURITY_ATTRIBUTES structure. It is the caller's
//    responsibility to properly initialize the structure and to free 
//    the structure's lpSecurityDescriptor member when the caller has
//    finished using it. To free the structure's lpSecurityDescriptor 
//    member, call the LocalFree function.
// 
// Return value:
//    FALSE if the address to the structure is NULL. 
//    Otherwise, this function returns the value from the
//    ConvertStringSecurityDescriptorToSecurityDescriptor function.
BOOL CreateMyDACL(SECURITY_ATTRIBUTES * pSA)
{
     // Define the SDDL for the DACL. This example sets 
     // the following access:
     //     Built-in guests are denied all access.
     //     Anonymous logon is denied all access.
    //     Authenticated users are allowed read/write/execute access.
     //     Administrators are allowed full control.
     // Modify these values as needed to generate the proper
     // DACL for your application. 
     TCHAR * szSD = TEXT("D:")       // Discretionary ACL
       TEXT("(D;OICI;GA;;BG)")     // Deny access to built-in guests
        TEXT("(D;OICI;GA;;;AN)")     // Deny access to anonymous logon
        TEXT("(A;OICI;GRGWGX;;;AU)") // Allow read/write/execute to authenticated users
        TEXT("(A;OICI;GA;;;BA)");    // Allow full control to administrators

    if (NULL == pSA)
        return FALSE;
     return ConvertStringSecurityDescriptorToSecurityDescriptor(
                szSD,
                SDDL_REVISION_1,
                &(pSA->lpSecurityDescriptor),
                NULL);
}
View Code

可保安全對象

  一個安全對象有一個安全描述符。所有有名字的 Windows 對象都是安全的。有些沒有名字的對象,例如:進程和線程對象也有安全描述符。對於大多數安全對象來說,你可以在創建對象的時候指定一個對象的安全描述符。例如:你能在 CreateFile 和 CreateProcess 函數中指定安全描述符。
  另外, Windows 安全函數是你能夠為操作系統創建的而不是 Windows 創建的安全對象得到和設置安全信息。 Windows 安全函數也提供支持私有使用安全描述符和程序定義對象。更多關於私有安全對象信息參見客戶服務器訪問控制。
  每個安全對象定義它自己的一系列訪問權限,並且它擁有的映射通用訪問權限。更多關於指定和通用訪問權限的信息,參見對象類型總覽
  下表顯示了函數來操作通用安全對象的安全信息:

對象類型

安全描述符函數

NTFS文件系統的文件和目錄

GetNamedSecurityInfo , SetNamedSecurityInfo, GetSecurityInfo, SetSecurityInfo

Named pipes

Anonymous pipes

GetSecurityInfo , SetSecurityInfo

Processes

Threads

GetSecurityInfo , SetSecurityInfo

File-mapping objects

GetNamedSecurityInfo , SetNamedSecurityInfo, GetSecurityInfo, SetSecurityInfo

Access tokens

SetKernelObjectSecurity , GetKernelObjectSecurity

Window-management objects ( window stations and desktops)

GetSecurityInfo , SetSecurityInfo

Registry keys

GetNamedSecurityInfo , SetNamedSecurityInfo, GetSecurityInfo, SetSecurityInfo

Windows services

GetNamedSecurityInfo , SetNamedSecurityInfo, GetSecurityInfo, SetSecurityInfo

Local or remote printers

GetNamedSecurityInfo , SetNamedSecurityInfo, GetSecurityInfo, SetSecurityInfo

Network shares

GetNamedSecurityInfo , SetNamedSecurityInfo, GetSecurityInfo, SetSecurityInfo

Interprocess synchronization objects (events, mutexes, semaphores, and waitable timers)

GetNamedSecurityInfo , SetNamedSecurityInfo, GetSecurityInfo, SetSecurityInfo

Job objects

GetNamedSecurityInfo , SetNamedSecurityInfo, GetSecurityInfo, SetSecurityInfo

Directory service objects

These objects are handled by Active Directory Objects. See Active Directory Service Interfaces.

 

登錄會話

  一個登錄繪畫從用戶登錄到計算機時候開始。所有登錄會話中的進程有相同的基本訪問標記。訪問標記包含登錄會話相關的安全上下文,包含用戶的 SID 和登錄標示以及登錄 SID 。

登錄 SID

  一個安全標示符( SID )用來表示登錄會話。你可以使用 DACL 中的登錄 SID 來在登錄會話過程中控制訪問。登錄 SID 只有在用戶登出的時候無效。登錄 SID 是計算機運行的時候唯一的。沒有其他會話有系統的 SID 。然而,可能的登錄 SID 集合在計算機啟動的時候被復位。為了從訪問標記中返回登錄 SID ,為 TokenGroups 調用 GetTokenInformation 函數。

訪問標記

  一個訪問標記包含登錄會話的安全信息。系統在用戶登錄的時候創建一個安全標記,每個進程執行用戶由於的標記副本。標記表示用戶、用戶組和用戶權限。系統使用標記來控制訪問安全對象和控制用戶在本地計算機上執行各種系統相關操作。兩種訪問標記:私有的和偽裝的。

偽裝標記:

  一個被創建來捕獲客戶進程安全信息、允許服務器在安全操作中偽裝客戶進程的訪問標記。

主標記:

  一個 Windows 內核創建的標記。可能分配給一個進程來表示默認的進程安全信息。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM