windows系统的安全性基础 -- 访问控制

最近看了一下msdn上关于windows的访问控制模型。访问控制就是“适当人使用适当的资源right persons use right resources.”

所以,

第一步,操作系统要认证Authentication, 验证是否是用户声明的用户身份。验证通过,以后,


第二步,操作系统要授权Authorization,   用户a要读取一个文件,操作系统检查文件的安全描述符security descriptor;

               如果“拥有读取权限的用户列表”里面存储了“用户a”,那么,操作系统继续开始文件的读取操作;

               这个过程就是“授权” authorization;


这个文章主要讲一下授权(Authorization),授权里面主要看看访问控制(Access Control Model);


1) 用户token

用户登录以后,操作系统给用户一个access token,里面主要存放了用户的权限privileges, 比如关机,调试,备份系统等等。

用户创建进程,这个进程就复制这个用户的token到进程信息中,进程创建线程(包括主线程),线程自动得到这个token,另外,线程可以“假冒”某个客户身份,impersonate,线程得到其他用户的token‘(登录,或者参数传递进来),就可以代表这个用户去访问只有这个用户可以访问的资源。

token里面还存储了用户的安全标识符security identifier.

=======================

用户token信息的打印

=======================

void DumpTokenInfo(void)
{
    HANDLE hToken = NULL;
    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
        return ;
    DWORD retLen = 0;
    GetTokenInformation(hToken, TokenGroupsAndPrivileges, NULL, 0, &retLen);

    TOKEN_GROUPS_AND_PRIVILEGES * pTgap = (TOKEN_GROUPS_AND_PRIVILEGES * )LocalAlloc(0, retLen);
    GetTokenInformation(hToken, TokenGroupsAndPrivileges, pTgap, retLen, &retLen);

    // 查询sid数组信息
    printf("\n===============Sids=====================\n");
    for (DWORD i = 0; i < pTgap->SidCount; ++i)
    {
        PSID pSid = pTgap->Sids[i].Sid;
        SID_NAME_USE sidType;
        char szName [MAX_PATH] = "";
        DWORD dwNameLen = MAX_PATH;
        char szDomain [MAX_PATH] = "";
        DWORD dwDomainLen = MAX_PATH;
        LookupAccountSidA(NULL
            , pSid
            , szName, &dwNameLen
            , szDomain, &dwDomainLen
            , &sidType);

        printf("Sids[%d] = %s@%s\n", i, szName, szDomain);
    }

    // 查询权限信息
    printf("\n===============Priveleges=====================\n");
    for (DWORD i = 0; i < pTgap->PrivilegeCount; ++i)
    {
        char szName [MAX_PATH] = "";
        DWORD dwNameLen = MAX_PATH;
        LookupPrivilegeNameA(NULL, &pTgap->Privileges[i].Luid, szName, &dwNameLen);

        printf("Privileges[%d] = %s\n", i, szName);
    }
}
/************************************************************************
0:001> !token <<<<windbg打印出来的token信息>>>>
/
Thread is not impersonating. Using process token...
TS Session ID: 0
User: S-1-5-21-2233661284-422353248-3399546490-500
Groups: 
00 S-1-5-21-2233661284-422353248-3399546490-513
Attributes - Mandatory Default Enabled 
01 S-1-1-0
Attributes - Mandatory Default Enabled 
02 S-1-5-32-544
Attributes - Mandatory Default Enabled Owner 
03 S-1-5-32-545
Attributes - Mandatory Default Enabled 
04 S-1-5-4
Attributes - Mandatory Default Enabled 
05 S-1-5-11
Attributes - Mandatory Default Enabled 
06 S-1-5-15
Attributes - Mandatory Default Enabled 
07 S-1-5-5-0-48147
Attributes - Mandatory Default Enabled LogonId 
08 S-1-2-0
Attributes - Mandatory Default Enabled 
09 S-1-5-64-10
Attributes - Mandatory Default Enabled 
Primary Group: S-1-5-21-2233661284-422353248-3399546490-513
Privs: 
00 0x000000017 SeChangeNotifyPrivilege           Attributes - Enabled Default 
01 0x000000008 SeSecurityPrivilege               Attributes - Enabled 
02 0x000000011 SeBackupPrivilege                 Attributes - 
03 0x000000012 SeRestorePrivilege                Attributes - 
04 0x00000000c SeSystemtimePrivilege             Attributes - Enabled 
05 0x000000013 SeShutdownPrivilege               Attributes - Enabled 
06 0x000000018 SeRemoteShutdownPrivilege         Attributes - Enabled 
07 0x000000009 SeTakeOwnershipPrivilege          Attributes - Enabled 
08 0x000000014 SeDebugPrivilege                  Attributes - Enabled 
09 0x000000016 SeSystemEnvironmentPrivilege      Attributes - Enabled 
10 0x00000000b SeSystemProfilePrivilege          Attributes - Enabled 
11 0x00000000d SeProfileSingleProcessPrivilege   Attributes - Enabled 
12 0x00000000e SeIncreaseBasePriorityPrivilege   Attributes - Enabled 
13 0x00000000a SeLoadDriverPrivilege             Attributes - Enabled 
14 0x00000000f SeCreatePagefilePrivilege         Attributes - Enabled 
15 0x000000005 SeIncreaseQuotaPrivilege          Attributes - Enabled 
16 0x000000019 SeUndockPrivilege                 Attributes - Enabled 
17 0x00000001c SeManageVolumePrivilege           Attributes - Enabled 
18 0x00000001d SeImpersonatePrivilege            Attributes - Enabled Default 
19 0x00000001e SeCreateGlobalPrivilege           Attributes - Enabled Default 
Auth ID: 0:c32f
Impersonation Level: Anonymous
TokenType: Primary
Is restricted token: no.
************************************************************************/



=======================

模仿客户存取特殊权限文件

=======================

#include <sys/stat.h>
#include <fcntl.h>
#include <io.h>

int main(int argc, char * argv[])
{
    char szCmd [0x20];
    printf("ImpersonateLoggedOnUser? [Y/N]>");
    gets(szCmd);

    // 模仿用户
    if (!_strnicmp(szCmd, "Y", 1))
    {
        HANDLE hToken = INVALID_HANDLE_VALUE;
        if (!LogonUserA("test2"
                        , "."
                        , "test2"
                        , LOGON32_LOGON_INTERACTIVE
                        , LOGON32_PROVIDER_DEFAULT
                        , &hToken))
        {
            printf("fail to LogonUserA, error %d\n", GetLastError());
            return -1;
        }

        if (!ImpersonateLoggedOnUser(hToken))
        {
            printf("fail to ImpersonateLoggedOnUser, error %d\n", GetLastError());
            return -1;
        }
    }
    
    // 实际上是访问文件所在的文件夹信息
    struct _stat _st;
    if (_stat("f:\\test.txt", &_st))
        return -1;

    printf("fsize=%d\n", _st.st_size);

    // 真正访问文件
    int fd = open("f:\\test.txt", O_RDONLY);
    if (fd > 0)
    {
        printf("open file ok.\n");
        close(fd);
    }
    else
    {
        printf("open failed %d.\n", GetLastError());
        return -1;
    }

    getchar();
    return 0;
}


2) 安全描述符

操作系统中的所有资源对象(进程,线程,文件,信号量。。。)都有一个安全描述符,来描述这个对象可以被哪些用户访问,安全描述符存放2个列表,discretionary access control list (DACL),sacl。

dacl中存放这ace(access control entries),一个ace包含一个sid和这个sid相关的的访问权(拒绝,允许,审计)。

========================

安全描述符信息的打印

========================

#include "accctrl.h"
#include "aclapi.h"
#pragma comment(lib, "advapi32.lib")

/*调整权限*/
BOOL SetPrivilege(
                  HANDLE hToken,          // access token handle
                  LPCTSTR lpszPrivilege,  // name of privilege to enable/disable
                  BOOL bEnablePrivilege   // to enable or disable privilege
                  ) 
{
    TOKEN_PRIVILEGES tp;
    LUID luid;

    if ( !LookupPrivilegeValue( 
        NULL,            // lookup privilege on local system
        lpszPrivilege,   // privilege to lookup 
        &luid ) )        // receives LUID of privilege
    {
        printf("LookupPrivilegeValue error: %u\n", GetLastError() ); 
        return FALSE; 
    }

    tp.PrivilegeCount = 1;
    tp.Privileges[0].Luid = luid;
    if (bEnablePrivilege)
        tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    else
        tp.Privileges[0].Attributes = 0;

    // Enable the privilege or disable all privileges.
    if ( !AdjustTokenPrivileges(
        hToken, 
        FALSE, 
        &tp, 
        sizeof(TOKEN_PRIVILEGES), 
        (PTOKEN_PRIVILEGES) NULL, 
        (PDWORD) NULL) )
    { 
        printf("AdjustTokenPrivileges error: %u\n", GetLastError() ); 
        return FALSE; 
    } 
    if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
    {
        printf("The token does not have the specified privilege. \n");
        return FALSE;
    } 
    return TRUE;
}

int main(void)
{
    DWORD dwRtnCode = 0;
    PSID pSidOwner = NULL, pSidGroup=NULL;
    PACL pDacl = NULL, pSacl = NULL;
    BOOL bRtnBool = TRUE;
    LPTSTR AcctName = NULL;
    LPTSTR DomainName = NULL;
    DWORD dwAcctName = 1, dwDomainName = 1;
    SID_NAME_USE eUse = SidTypeUnknown;
    HANDLE hFile;
    PSECURITY_DESCRIPTOR pSD = NULL;
    HANDLE hToken = NULL;

    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &hToken))
        return -1;
    
    SetPrivilege(hToken, SE_SECURITY_NAME, TRUE);


    // Get the handle of the file object.
    hFile = CreateFile(
        TEXT("h:\\workspace\\Test\\test2\\test2\\test2.cpp"),
        GENERIC_READ | READ_CONTROL | ACCESS_SYSTEM_SECURITY,
        FILE_SHARE_READ,
        NULL,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        NULL);

    // Check GetLastError for CreateFile error code.
    if (hFile == INVALID_HANDLE_VALUE) {
        DWORD dwErrorCode = 0;

        dwErrorCode = GetLastError();
        _tprintf(TEXT("CreateFile error = %d\n"), dwErrorCode);
        return -1;
    }

    // Get the owner SID of the file.
    dwRtnCode = GetSecurityInfo(
        hFile,
        SE_FILE_OBJECT,
        DACL_SECURITY_INFORMATION
        | SACL_SECURITY_INFORMATION
        | OWNER_SECURITY_INFORMATION
        | GROUP_SECURITY_INFORMATION
        , 
        &pSidOwner,
        &pSidGroup,
        &pDacl,
        &pSacl,
        &pSD);

    // Check GetLastError for GetSecurityInfo error condition.
    if (dwRtnCode != ERROR_SUCCESS) {
        DWORD dwErrorCode = 0;

        dwErrorCode = GetLastError();
        _tprintf(TEXT("GetSecurityInfo error = %d\n"), dwErrorCode);
        return -1;
    }

    // First call to LookupAccountSid to get the buffer sizes.
    bRtnBool = LookupAccountSid(
        NULL,           // local computer
        pSidOwner,
        AcctName,
        (LPDWORD)&dwAcctName,
        DomainName,
        (LPDWORD)&dwDomainName,
        &eUse);

    // Reallocate memory for the buffers.
    AcctName = (LPTSTR)GlobalAlloc(
        GMEM_FIXED,
        dwAcctName);

    // Check GetLastError for GlobalAlloc error condition.
    if (AcctName == NULL) {
        DWORD dwErrorCode = 0;

        dwErrorCode = GetLastError();
        _tprintf(TEXT("GlobalAlloc error = %d\n"), dwErrorCode);
        return -1;
    }

    DomainName = (LPTSTR)GlobalAlloc(
        GMEM_FIXED,
        dwDomainName);

    // Check GetLastError for GlobalAlloc error condition.
    if (DomainName == NULL) {
        DWORD dwErrorCode = 0;
        dwErrorCode = GetLastError();
        _tprintf(TEXT("GlobalAlloc error = %d\n"), dwErrorCode);
        return -1;
    }
    // Second call to LookupAccountSid to get the account name.
    bRtnBool = LookupAccountSid(
        NULL,                   // name of local or remote computer
        pSidOwner,              // security identifier
        AcctName,               // account name buffer
        (LPDWORD)&dwAcctName,   // size of account name buffer 
        DomainName,             // domain name
        (LPDWORD)&dwDomainName, // size of domain name buffer
        &eUse);                 // SID type

    // Check GetLastError for LookupAccountSid error condition.
    if (bRtnBool == FALSE) {
        DWORD dwErrorCode = 0;
        dwErrorCode = GetLastError();
        if (dwErrorCode == ERROR_NONE_MAPPED)
            _tprintf(TEXT("Account owner not found for specified SID.\n"));
        else 
            _tprintf(TEXT("Error in LookupAccountSid.\n"));
        return -1;
    } else if (bRtnBool == TRUE) 

    // Print the account name.
    _tprintf(TEXT("Account owner = %s\n"), AcctName);

    // 打印dacl的信息
    if (NULL == pDacl || !IsValidAcl(pDacl)) return -1;
    ACL_SIZE_INFORMATION asi;
    if (!GetAclInformation(pDacl, &asi, sizeof(asi), AclSizeInformation))
        return -1;

    for (int i = 0; i < asi.AceCount; ++i)
    {
        void * pAce = NULL;
        GetAce(pDacl, i, &pAce);
        printf("Access Credential Entries[%d] is at %p\n", i, pAce);
    }
    return 0;
}

=======================

创建带安全属性的对象-文件

=======================

void CreateKeyWithSecDesc(char * filePath)
{
    DWORD dwRes, dwDisposition;

    LONG lRes;

    // 为EveryOne组创建一个知名sid
    SID_IDENTIFIER_AUTHORITY SIDAuthWorld 
        = SECURITY_WORLD_SID_AUTHORITY;
    PSID pEveryoneSID = NULL;
    if(!AllocateAndInitializeSid(&SIDAuthWorld, 1,
                                SECURITY_WORLD_RID,
                                0, 0, 0, 0, 0, 0, 0,
                                &pEveryoneSID))
    {
        _tprintf(_T("AllocateAndInitializeSid Error %u\n"), GetLastError());
        goto Cleanup;
    }

    // 为ACE初始化一个"显示访问"结构
    // 这个ACE允许EveryOne读取这个对象
    EXPLICIT_ACCESS ea[2];
    ZeroMemory(&ea, 2 * sizeof(EXPLICIT_ACCESS));
    ea[0].grfAccessPermissions = FILE_GENERIC_READ | FILE_GENERIC_EXECUTE;
    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;

    // 为管理员组创建一个sid
    SID_IDENTIFIER_AUTHORITY SIDAuthNT 
        = SECURITY_NT_AUTHORITY;
    PSID pAdminSID = NULL;
    if(! AllocateAndInitializeSid(&SIDAuthNT, 2,
                                SECURITY_BUILTIN_DOMAIN_RID,
                                DOMAIN_ALIAS_RID_ADMINS,
                                0, 0, 0, 0, 0, 0,
                                &pAdminSID)) 
    {
        _tprintf(_T("AllocateAndInitializeSid Error %u\n"), GetLastError());
        goto Cleanup; 
    }

    // 为ACE初始化一个"显示访问"结构
    // 这个ACE允许管理员组完全控制这个对象的权力
    ea[1].grfAccessPermissions = FILE_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;

    // 创建一个新的acl,包含以上设置的2个ACE
    // ACE机器可读的,所以用“显示访问”结构
    // 去创建ACL
    PACL pACL = NULL;
    dwRes = SetEntriesInAcl(2, ea, NULL, &pACL);
    if (ERROR_SUCCESS != dwRes) 
    {
        _tprintf(_T("SetEntriesInAcl Error %u\n"), GetLastError());
        goto Cleanup;
    }

    // 分配一个最小"安全描述符".  
    PSECURITY_DESCRIPTOR pSD = NULL;
    pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, 
        SECURITY_DESCRIPTOR_MIN_LENGTH); 
    if (NULL == pSD) 
    { 
        _tprintf(_T("LocalAlloc Error %u\n"), GetLastError());
        goto Cleanup; 
    } 

    // 初始化"安全描述符"
    if (!InitializeSecurityDescriptor(pSD,
        SECURITY_DESCRIPTOR_REVISION)) 
    {  
        _tprintf(_T("InitializeSecurityDescriptor Error %u\n"),
            GetLastError());
        goto Cleanup; 
    } 

    // 把ACL添加到“安全描述符 ”
    if (!SetSecurityDescriptorDacl(pSD, 
        TRUE,     // bDaclPresent flag   
        pACL, 
        FALSE))   // not a default DACL 
    {  
        _tprintf(_T("SetSecurityDescriptorDacl Error %u\n"),
            GetLastError());
        goto Cleanup; 
    } 

    // 把安全描述符设置到安全属性结构中
    SECURITY_ATTRIBUTES sa;
    sa.nLength = sizeof (SECURITY_ATTRIBUTES);
    sa.lpSecurityDescriptor = pSD;
    sa.bInheritHandle = FALSE;

    // 使用安全属性结构作为参数,
    // 把安全描述符信息设置到新创建对象中
    HANDLE hFile = CreateFileA(filePath
        , FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE
        , FILE_SHARE_READ | FILE_SHARE_WRITE
        , &sa
        , CREATE_ALWAYS
        , FILE_ATTRIBUTE_NORMAL
        , NULL);

    if (hFile != INVALID_HANDLE_VALUE)
    {
        CloseHandle(hFile);
    }
    else
        _tprintf(_T("CreateFile result %u\n"), lRes );

Cleanup:

    if (pEveryoneSID) 
        FreeSid(pEveryoneSID);
    if (pAdminSID) 
        FreeSid(pAdminSID);
    if (pACL) 
        LocalFree(pACL);
    if (pSD) 
        LocalFree(pSD);
    return;

}


3) 授权的过程

一个线程访问一个资源,系统首先检查这个线程的impersionate token,如果没有就是用进程的access token,从里面获取到sid,然后遍历dacl的ace,查看和这个sid相关的每一个ace,知道找的一个拒绝或者允许的ace,就返回。


http://msdn.microsoft.com/en-us/library/windows/desktop/aa374860(v=VS.85).aspx
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值