Nt/2000/xp平台下的存储控制模型(Access Control Model)

鉴于在nt类操作系统下开发程序时有可能涉及操作注册表,读写文件和操控服务等内容,而为使这类程序在不同帐户下皆可正确运行就需要了解nt类操作系统的存储控制模型,所以才写这篇文章。这篇文章所涉及大部分内容可在msdn找到相关说明,小部分内容来自个人经验。错漏之处还望斧正。

 

基本概念及缩写:

 

SID(security identifier):用于唯一标识用户或组的变长结构

 

access token存储令牌包含每个登录帐户的安全信息。每当用户登录系统时,系统为其建立一个access token,而此用户所执行的进程拥有此access token的一份拷贝。Access token 中包含的内容有

l         User SID

l         Group SIDs

l         Privilege Information

l         Other access Information

 

ACE( access control entry) :包含一系列存储权限及谁拥有这种权限的说明。

 

ACL(access control list): 一个ACE的链表,用于说明某个安全对象可以被谁以什么样的权限进行操作。

 

DACLdiscretionary access control list):由安全对象的拥有者(即创建者)控制的ACL

 

Trustee: a trustee is the user account, group account, or logon session to which an access control entry (ACE) applies

 

利用这些概念,我们来看一下,对安全对象进行操作要经过那些步骤。(见图1)

 

这个过程是这样,系统把线程的Access TokentrusteeDACL中每一个ACLtrustee相比较直到满足下列某一个条件:

l         一个ACE清楚的表明某项操作对这个Access Token无效。比如Thread A的访问过程。

l         一个ACE清楚的表明能够接受这个Access Token所要求的操作。比如Thread B要求进行Write ,Read or Execute操作。

l         所有ACE已被检查过但仍然有一项或多项权限没有被清楚的允许。此时称做隐式禁止(implicitly denied)。

另外,如果ACEDACL中有不同的排列顺序,对于某个Access Token,可能有完全不同的结果。比如ACE 2排在ACE 1 前面的话,Thread A将可以对此对象进行写操作。

(图1 from msdn

1

关于C2-Level Security的一些重要指标

l         必须能通过操控个人用户或用户组的权限来控制对资源的访问。

l         内存需要受到保护,一个进程所释放的内存不能被另外的进程读到。同样文件系统也要保证被删除的文件不能被读到。

l         用户能够用唯一的方式标识自己,All auditable actions must identify the user performing the action

l         系统管理员要能够对安全事件进行检查。但安全事件的存取权限要由authorized administrators进行设定。

l         系统要能够保证自己不被干扰。比如:不允许对正在运行的系统及相关的系统文件进行调整。

()

       在涉及其他之前,我们先来看一段可能会出问题的程序。

   if(ERROR_SUCCESS !=RegCreateKeyExW(HKEY_LOCAL_MACHINE,L"Software""007h",0,NULL,

  REG_OPTION_NON_VOLATILE,KEY_WRITE,NULL,&hkey,NULL))

{return FALSE;}

 

 if(ERROR_SUCCESS !=RegSetValueEx(hkey,lpItem,0,REG_SZ,(LPBYTE)”90”,2))

{

RegCloseKey(hkey); return FALSE;

}

RegCloseKey(hkey);    

(程序1

 这段程序很简单,就是打开注册表,并写值。在98或者管理员权限下基本上不会出现什么问题。但存在什么样的潜在问题呢?我们做这样的假设,这段代码运行在用户态的打印机驱动程序的某个DDI接口中,比如DrvEnablePDEV。这样当不同用户进行打印时这段代码都需要被调用。于是问题出现了,在其他用户权限下,有可能打开或者设置值失败。GetLastError()返回5Access denied)。原因是当你建立相关子键"Software""007h”时使用了NULL做为安全权限(lpSecurityAttributes)地参数。使用NULL意味着从父键直接继承DACL,而在这个DACL中一旦不包含对你所使用的帐户赋予权限的ACE,你对注册表的相关操作必然失败。(枚举"Software”的各个ACE的代码见后,但读懂ACE字符串有点难度,简单来说就是Built-in users只有对"Software”进行读的权利,所以Users组和Guest组的用户将无法写你所建立的子键007h”,因为用上述方式建立的子键的DACL继承自"Software”)。为避免这种情况,建立注册表键时要明确制定安全权限。代码如下(from msdn 有更改)

这段代码建立一个管理员可以进行任何操作,任何用户都可以读写的子键,程序和相关结构的说明将在下节进行。

    SECURITY_ATTRIBUTES uSecurityAttributes;

      

    PSID pEveryoneSID = NULL, pAdminSID = NULL;

    PACL pACL = NULL;

    PSECURITY_DESCRIPTOR pSD = NULL;

    EXPLICIT_ACCESS ea[2];

 SID_IDENTIFIER_AUTHORITY SIDAuthWorld =  SECURITY_WORLD_SID_AUTHORITY;

    SID_IDENTIFIER_AUTHORITY SIDAuthNT =         SECURITY_NT_AUTHORITY;

    SECURITY_ATTRIBUTES sa;

    LONG lRes;

    HKEY hkSub = NULL;

 

    // Create a well-known SID for the Everyone group.

    BOOL bResult=AllocateAndInitializeSid(&SIDAuthWorld,  1,

                     SECURITY_WORLD_RID,

                     0, 0, 0, 0, 0, 0, 0,

                     &pEveryoneSID);

                    

    // Initialize an EXPLICIT_ACCESS structure for an ACE.

    // The ACE will allow Everyone read access to the key.

    ZeroMemory(&ea, 2*sizeof(EXPLICIT_ACCESS));

    ea[0].grfAccessPermissions = KEY_READ|KEY_WRITE ;

    ea[0].grfAccessMode = SET_ACCESS;

   ea[0].grfInheritance= NO_INHERITANCE;

    ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;

    ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;

    ea[0].Trustee.ptstrName = (LPTSTR) pEveryoneSID;

            

       AllocateAndInitializeSid(&SIDAuthNT, 2,

                     SECURITY_BUILTIN_DOMAIN_RID,

                     DOMAIN_ALIAS_RID_ADMINS,

                     0, 0, 0, 0, 0, 0,

                     &pAdminSID);

              // Initialize an EXPLICIT_ACCESS structure for an ACE.

                      // The ACE will allow the Administrators group full access to the key.

              ea[1].grfAccessPermissions = KEY_ALL_ACCESS;

              ea[1].grfAccessMode = SET_ACCESS;

              ea[1].grfInheritance= NO_INHERITANCE;

              ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;

              ea[1].Trustee.TrusteeType = TRUSTEE_IS_GROUP;

              ea[1].Trustee.ptstrName = (LPTSTR) pAdminSID;

 

           // Create a new ACL that contains the new ACEs.

           dwRes = SetEntriesInAcl(2, ea, NULL, &pACL);

          

               // Initialize a security descriptor. 

           pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR,

                             SECURITY_DESCRIPTOR_MIN_LENGTH);

                            

        InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION);

       

        SetSecurityDescriptorDacl(pSD,

            TRUE,     // bDaclPresent flag  

            pACL,

            FALSE);

           

            // Initialize a security attributes structure.

           sa.nLength = sizeof (SECURITY_ATTRIBUTES);

           sa.lpSecurityDescriptor = pSD;

           sa.bInheritHandle = FALSE;

              

if ((dwErr=RegCreateKeyExW(HKEY_LOCAL_MACHINE,L"Software""800",0,NULL,

REG_OPTION_NON_VOLATILE,KEY_READ|KEY_WRITE,&sa,&hkey,NULL))!=ERROR_SUCCESS)

{ return ; }

else   if ((dwErr=RegSetValueEx(hkey,lpItem,0,REG_SZ,(LPBYTE)lpVer90,2))

!=ERROR_SUCCESS)

{ RegCloseKey(hkey);return; }

             

       RegCloseKey(hkey);

               if(pAdminSID)

              FreeSid(pAdminSID);

 

       if (pEveryoneSID)

        FreeSid(pEveryoneSID);

    if (pACL)

        LocalFree(pACL);

    if (pSD)

        LocalFree(pSD);

(程序2

下面为读取当前注册表键安全信息并把它转为字符串的程序,转化后的字符串的解析,参见msdn.

       DWORD dwRes;

       PACL pOldDACL = NULL;

       PSECURITY_DESCRIPTOR pSD = NULL;

       PSID pprimarysid=NULL,pownersid=NULL;

       LPSTR pstring;

 

       HKEY hObject;

 

       if(ERROR_SUCCESS!=RegOpenKeyEx(HKEY_LOCAL_MACHINE,"Software""800",0,KEY_READ,&hObject))

                     return 0;

       // Get a pointer to the existing DACL.

      

       dwRes = GetSecurityInfo((HANDLE)hObject, SE_REGISTRY_KEY ,

              DACL_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION

|OWNER_SECURITY_INFORMATION,

              &pownersid, &pprimarysid, &pOldDACL, NULL, &pSD);

 

       ConvertSecurityDescriptorToStringSecurityDescriptor(pSD,SDDL_REVISION_1,

              DACL_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION

|OWNER_SECURITY_INFORMATION,

              &pstring,NULL);

 

 

    if(pSD != NULL)

        LocalFree((HLOCAL) pSD);

 

       if(pstring!=NULL)

              LocalFree((HLOCAL)pstring);

 

       RegCloseKey(hObject);

(程序 3)

posted on 2008-03-10 10:08  highmayor  阅读(337)  评论(0编辑  收藏  举报

导航