Windows API 用户、认证和对象安全
来源:互联网 发布:变色龙运行mac黑屏 编辑:程序博客网 时间:2024/05/29 17:41
本文转自:http://www.cnblogs.com/mydomain/archive/2011/02/23/1962655.html
Windows系统具有很完善的安全和认证机制,称作访问控制机制。程序的执行主体(线程)在访问对象(文件、事件等)时,系统会根据线程的“权限”和线程需要访问的对象所具有的访问控制列表(ACL)中的“安全描述符”是否匹配来进行认证,决定一个线程是否可以操作一个对象。
一、基本概念
1、A需要访问(Access)B,A就是访问的主体,B就是访问的客体。A的“访问令牌”和B的安全描述符共同决定了A是否可以访问B。
访问的主体是进程。在系统中,线程才是程序执行的流程,因此只有线程才能操作对象。每个线程都是属于一个进程的,线程并没有属于自己的权限,而是来源于线程所属于的进程。一个进程中的所有线程都具有同样的权限。一个线程能访问哪些对象,能进行哪此操作,是由线程权限决定的。
访问的客体是安全对象,所有被访问的对象都具有安全描述符,包括了文件、注册表、事件(Event)、互斥(Mutex)、管道等。
2、进程的权限继承自创建进程用户和用户所属的用户组。用户有专用数据结构来表示权限—访问令牌(Access Token)。访问令牌包括两个部分:一个是令牌所表示的用户,包括用户标识符(SID),用户所属的用户组等;另一部分是“权限”(Privilege)。
在进程访问安全对象时,会用到SID。每个安全对象都有访问控制列表(ACL),ACL说明了哪些用户( SID)能访问本对象,哪些不能,以及能进行哪种访问等。而“权限”在访问某个具体的安全对象时并没有作用,“权限”是表示进程是否能够进行特定的系统操作,如关闭系统、修改系统时间、加载设备驱动等。
创建进程的API函数是CreateProcess,CreateProcess函数所创建的进程使用的访问令牌是当前登录用户的访问令牌。
可以指定进程的用户。通过CreateProcessAsUser和CreateProcessWithTokenW等API函数,在创建前需要先得到用户的令牌,可以使用LogonUser登录用户(是否可以同时登录多个用户受操作系统版本限制),LogonUser函数用返回用户的令牌。
如果需要得到进程和线程的访问令牌,可以使用OpenProcessToken、OpenThreadToken等函数。获取令牌中的信息可以使用API函数GetTokenInformation。如果需要修改权限,可以使用AdjustTokenPrivileges等函数。
3、进程的系统操作权限
进程的权限特指进程是否能够进行各种系统操作,例如是否可以关闭系统,是否能够修改系统时间,是否能够加载设备驱动等。权限是一个列表,每种权限是列表中的一项。权限列表存在于进程的访问令牌中。
权限有很多种,每一种表示了一个特定的操作是否能够进行,如果进程的访问令牌中的权限列表中有这个权限,则表示进程可以进行这种操作,比如SE_LOAD_DRIVER_ NAME表示进程可以加载驱动。
4、安全对象
Windows系统几乎所有的对象都有安全属性,包括文件、文件夹、注册表、线程同步对象、进程间通信对象、网络共享等,进程和线程也可以是其他进程的操作对象,所以进程和线程也是安全对象。
在创建对象时都可以指定对象的安全属性,比如CreateFile、CreatePipe、CreateProcess、RegCreateKeyEx和RegSaveKeyEx等,SECURITY_ATTRIBUTES结构用于指定对象的安全属性。
GetNamedSecurityInfo、 GetSecurityInfo、SetSecurityInfo、 SetKernelObjectSecurity、SetNamedSecurityInfo等API函数可以获取和设置对象的安全属性。
对象的安全属性是以安全描述符(Security Descriptor)的形式存在的,安全描述符中包括了访问控制列表。
5、访问控制列表(ACL)
每个安全对象都有访问控制列表。访问控制列表有两种,一种是选择访问控制列表(discretionary access control list,DACL),另一种是系统访问控制列表(system access controllist,SACL)。DACL决定了用户或用户组是否能访问这个对象,SACL控制了尝试访问安全对象的检测信息的继承关系。
DACL是访问控制的关键。DACL中包括一个访问控制入口(Access Control
Entries,ACE)列表。ACE表明了用户(通过用户SID或用户组SID)是否能进行操作以及能进行哪种操作。在进行访问控制检测时,会依次检测DACL中的ACE,直到被允许或被拒绝。
ACE内容及线程访问令牌中的SID和DACL中的ACE的认证过程
二、示例代码
1、列举进程访问令牌内容和权限
显示进程的访问令牌内容
SDK安装目录下,Samples\Security\Authorization\MyToken
显示SID
获取SID可以通过LookupAccountName API函数。
Samples\Security\Authorization\TextSid
列举安全对象的安全描述符
Samples\Security\Authorization\Check_SD
修改安全描述符通过SetFileSecurity API
三、用户
增加
NetUserAdd API函数在系统中创建用户[4]
NetGroupAddUser
NetUserDel
NetUserEnum和NetLocalGroupEnum API函数分别用于列举指定主机中当前的所有用户和用户组。
示例用户操作
/* UNICODE */#ifndef UNICODE#define UNICODE#endif/* 头文件 */#include <stdio.h>#include <assert.h>#include <windows.h> #include <lm.h>#pragma comment(lib,"Netapi32.lib")/************************************** AddUser* 功能 增加用户* 参数 szServerName,主机名,如果为本机增加用户,设置为NULL* szUserName,用户名* szPassword,密码**************************************/int AddUser(LPWSTR szServerName, LPWSTR szUserName, LPWSTR szPassword){ USER_INFO_1 ui; DWORD dwLevel =1; // 使用 USER_INFO_1 作为参数 DWORD dwError =0; NET_API_STATUS nStatus; // 填充 USER_INFO_1 ui.usri1_name = szUserName; // 用户名 ui.usri1_password = szPassword; // 密码 ui.usri1_priv = USER_PRIV_USER; // privilege ui.usri1_home_dir = NULL; ui.usri1_comment = NULL; ui.usri1_flags = UF_SCRIPT; ui.usri1_script_path = NULL; // 调用 NetUserAdd 增加用户 nStatus = NetUserAdd(szServerName, dwLevel, (LPBYTE)&ui, &dwError); // 判断结果if (nStatus == NERR_Success) { wprintf((const wchar_t*)stderr, L"User %s has been successfully added on %s\n", szUserName, szServerName); } else { fprintf(stderr, "A system error has occurred: %d\n", nStatus); } return0;}/************************************** AddUserToGroup* 功能 为用户组增加用户* 参数 szServerName,主机名,如果为本机,设置为NULL* szUserName,用户名* szGroup,用户组名**************************************/int AddUserToGroup(LPWSTR szServerName, LPWSTR szUserName, LPWSTR szGroup){ NET_API_STATUS nStatus; // 调用 NetGroupAddUser nStatus = NetGroupAddUser( szServerName, szGroup, szUserName ); // 判断结果if (nStatus == NERR_Success) fwprintf(stderr, L"User %s has been successfully added on %s\n", szUserName, szServerName); else fprintf(stderr, "NetGroupAddUser A system error has occurred: %d\n", nStatus); return0;}/************************************** DelUser* 功能 删除用户* 参数 szServerName,主机名,如果为本机,设置为NULL* szUserName,用户名**************************************/int DelUser(LPWSTR szServerName, LPWSTR szUserName){ DWORD dwError =0; NET_API_STATUS nStatus; // 调用 NetUserDel 删除用户 nStatus = NetUserDel(szServerName, szUserName); // 判断并显示结果if (nStatus == NERR_Success) fwprintf(stderr, L"User %s has been successfully deleted on %s\n", szUserName, szServerName); else fprintf(stderr, "A system error has occurred: %d\n", nStatus); return0;}/************************************** int ListUsers(LPWSTR pszServerName)* 功能 列举用户* 参数 szServerName,主机名,如果为本机,设置为NULL**************************************/int ListUsers(LPWSTR pszServerName){ LPUSER_INFO_0 pBuf = NULL; LPUSER_INFO_0 pTmpBuf; DWORD dwLevel =0; DWORD dwPrefMaxLen = MAX_PREFERRED_LENGTH; DWORD dwEntriesRead =0; DWORD dwTotalEntries =0; DWORD dwResumeHandle =0; DWORD i; DWORD dwTotalCount =0; NET_API_STATUS nStatus; // 循环,直到可以成功调用 NetUserEnumdo { // 调用NetUserEnum函数 nStatus = NetUserEnum(pszServerName, dwLevel,// 这里设置为0,使用 LPUSER_INFO_0 返回结果 FILTER_NORMAL_ACCOUNT, // 只列举“正常”类型的用户 (LPBYTE*)&pBuf,// LPUSER_INFO_0 保存返回结果 // MAX_PREFERRED_LENGTH,内存由API分配,需要在之后调用NetApiBufferFree释放 dwPrefMaxLen, &dwEntriesRead,// 读了的 Entries&dwTotalEntries,// 一共的 Entries&dwResumeHandle); // 判断是否成功if ((nStatus == NERR_Success) || (nStatus == ERROR_MORE_DATA)) { if ((pTmpBuf = pBuf) != NULL) { // 循环读取用户信息for (i =0; (i < dwEntriesRead); i++) { assert(pTmpBuf != NULL); if (pTmpBuf == NULL) { fprintf(stderr, "An access violation has occurred\n"); break; } // 输出 wprintf(L"\t-- %s\n", pTmpBuf->usri0_name); // 下一个 pTmpBuf++; dwTotalCount++; } } } else fprintf(stderr, "A system error has occurred: %d\n", nStatus); // 释放内存if (pBuf != NULL) { NetApiBufferFree(pBuf); pBuf = NULL; } } while (nStatus == ERROR_MORE_DATA); // end do // 释放内存if (pBuf != NULL) NetApiBufferFree(pBuf); fprintf(stderr, "Total of %d users\n\n", dwTotalCount); return0;}/************************************** int ListGroup(LPWSTR pszServerName)* 功能 列举用户组* 参数 szServerName,主机名,如果为本机,设置为NULL**************************************/int ListGroup(LPWSTR pszServerName){ DWORD dwLevel =0; DWORD dwPrefMaxLen = MAX_PREFERRED_LENGTH; DWORD dwEntriesRead =0; DWORD dwTotalEntries =0; DWORD dwResumeHandle =0; DWORD i; DWORD dwTotalCount =0; NET_API_STATUS nStatus; LPLOCALGROUP_INFO_0 pBuf = NULL; LPLOCALGROUP_INFO_0 pTmpBuf; do// begin do { // 调用NetLocalGroupEnum 参数设置与NetLocalGroup类似 nStatus = NetLocalGroupEnum( pszServerName, 0, (LPBYTE*)&pBuf, dwPrefMaxLen, &dwEntriesRead, &dwTotalEntries, &dwResumeHandle); // 判断结果if ((nStatus == NERR_Success) || (nStatus == ERROR_MORE_DATA)) { if ((pTmpBuf = pBuf) != NULL) { // 循环输出for (i =0; (i < dwEntriesRead); i++) { assert(pTmpBuf != NULL); if (pTmpBuf == NULL) { fprintf(stderr, "An access violation has occurred\n"); break; } wprintf(L"\t-- %s\n", pTmpBuf->lgrpi0_name); pTmpBuf++; dwTotalCount++; } } } else fprintf(stderr, "A system error has occurred: %d\n", nStatus); // 释放内存if (pBuf != NULL) { NetApiBufferFree(pBuf); pBuf = NULL; } } while (nStatus == ERROR_MORE_DATA); // end do if (pBuf != NULL) NetApiBufferFree(pBuf); fprintf(stderr, "Total of %d groups\n\n", dwTotalCount); return0;}/************************************** ShowUsersInfo* 功能 显示指定用户的信息* 参数 szServerName,主机名,如果为本机,设置为NULL* pszUserName,用户名**************************************/int ShowUsersInfo(LPWSTR pszServerName,LPWSTR pszUserName){ DWORD dwLevel =4;// 使用 LPUSER_INFO_4 返回结果 LPUSER_INFO_4 pBuf = NULL; NET_API_STATUS nStatus; nStatus = NetUserGetInfo(pszServerName, pszUserName, dwLevel, // pBuf参数类型 (LPBYTE *)&pBuf); // 判断并输出结果if (nStatus == NERR_Success) { if (pBuf != NULL) { wprintf(L"\n\tAccount: %s\n", pBuf->usri4_name); wprintf(L"\tComment: %s\n", pBuf->usri4_comment); wprintf(L"\tUser comment: %s\n", pBuf->usri4_usr_comment); wprintf(L"\tFull name: %s\n", pBuf->usri4_full_name); wprintf(L"\tpriv: %d\n", pBuf->usri4_priv); } } else fprintf(stderr, "A system error has occurred: %d\n", nStatus); // 释放内存if (pBuf != NULL) NetApiBufferFree(pBuf); return0;}/************************************** wmain* 功能 入口函数,根据参数判断需要调用的功能函数* 参数 参见usage输出**************************************/int __cdecl wmain(int ac, wchar_t * av[]){ if (ac ==4&& lstrcmpW( av[1], L"-a") ==0) { AddUser(NULL, av[2], av[3]); } elseif (ac ==4&& lstrcmpW( av[1], L"-g") ==0) { AddUserToGroup(NULL, av[2], av[3]); } elseif (ac ==3&& lstrcmpW( av[1], L"-i") ==0) { ShowUsersInfo(NULL, av[2]); } elseif (ac ==2&& lstrcmpW( av[1], L"-i") ==0) { ListUsers(NULL); ListGroup(NULL); } elseif (ac ==3&& lstrcmpW( av[1], L"-d") ==0) { DelUser(NULL, av[2]); } else { printf("usage: \n" "\t %ws -a <username> <password> to add a user\n" "\t %ws -g <username> <group> add a user to a group" "\t %ws -i <username> to show user info\n" "\t %ws -d <username> to del a user\n", av[0], av[0], av[0], av[0]); } return0;}
参考
[1] 精通Windows API 函数、接口、编程实例
[2] http://www.cnblogs.com/mydomain/archive/2010/11/24/1887138.html
[3] http://msdn.microsoft.com/en-us/library/aa378184%28VS.85%29.aspx
[4] http://msdn.microsoft.com/en-us/library/aa370672%28VS.85%29.aspx
- Windows API 用户、认证和对象安全
- Windows 用户、认证和对象安全
- 用户,认证和对象安全
- 用户认证和安全
- Mongodb用户安全认证
- HiveServer2用户安全认证
- 10、Mongodb的用户认证和数据库的安全
- mongodb用户安全认证详解
- 16.用户管理、安全认证
- Mongdb安全和认证
- 用户认证和用户授权
- django 用户认证 user对象
- ASP.NET Windows用户认证
- 用户安全认证的registry server
- MongoDB 开启安全认证及创建用户
- [bigdata-023] pymongo 3.4和mongodb 2.x的安全机制导致的用户认证问题
- mongoDB安全认证和php安全处理
- windows安全对象学习
- 黑马程序员------------------泛型
- Git winxp实用出现Git.run() have no output问题解决办法
- ubuntu-10.04.4系统update以及upgrade失败解决办法
- stm32w108 Bootloader的使用
- .net(C#)命名规范
- Windows API 用户、认证和对象安全
- (数据结构)栈_迷宫求解(严蔚敏P50) _模仿
- 给树莓派安装看门狗
- 驱动第六天
- Android display架构
- SQL描述(3)
- 数据存储过程
- Android剖析和运行机制
- 编程之美--寻找最大的K个数