使用 C++ 设置默认进程安全级别

当客户端应用程序首次登录到 Windows Management Instrumentation (WMI) 时,它必须通过调用 CoInitializeSecurity 来设置默认进程安全级别。 COM 使用调用中的信息来确定另一个进程必须有多高的安全性才能访问客户端应用程序进程。

本主题包括以下部分:

对于大多数客户端应用程序,以下示例中显示的参数会为 WMI 设置默认安全性。

HRESULT hr = NULL;
hr = CoInitializeSecurity(
        NULL,                       // security descriptor
       -1,                          // use this simple setting
       NULL,                        // use this simple setting
       NULL,                        // reserved
       RPC_C_AUTHN_LEVEL_DEFAULT,   // authentication level  
       RPC_C_IMP_LEVEL_IMPERSONATE, // impersonation level
       NULL,                        // use this simple setting
       EOAC_NONE,                   // no special capabilities
       NULL);                          // reserved

if (FAILED(hr))
{
  CoUninitialize();
  cout << "Failed to initialize security. Error code = 0x"
       << hex << hr << endl;
  return;
}

代码需要以下引用和 #include 语句才能正确编译。

#define _WIN32_DCOM
#include <iostream>
using namespace std;
#include <Wbemidl.h>

#pragma comment(lib, "wbemuuid.lib")

将身份验证级别设置为 RPC_C_AUTHN_LEVEL_DEFAULT 后,DCOM 就可以协商身份验证级别,使之满足目标计算机的安全需求。 有关详细信息,请参阅使用 C++ 更改默认身份验证凭据使用 C++ 更改默认模拟设置

使用 C++ 更改默认身份验证凭据

默认身份验证凭据适用于大多数情况,但你可能需要在不同情况下使用不同的身份验证凭据。 例如,可能需要将加密添加到身份验证过程中。

下表列出并描述了不同级别的身份验证。

身份验证级别 说明
RPC_C_AUTHN_LEVEL_DEFAULT 默认安全身份验证。
RPC_C_AUTHN_LEVEL_NONE 无身份验证。
RPC_C_AUTHN_LEVEL_CONNECT 仅当客户端创建与服务器的关系时进行身份验证。
RPC_C_AUTHN_LEVEL_CALL 每次服务器收到 RPC 时进行身份验证。
RPC_C_AUTHN_LEVEL_PKT 每次服务器从客户端接收数据时进行身份验证。
RPC_C_AUTHN_LEVEL_PKT_INTEGRITY 验证数据包中的数据没有被修改。
RPC_C_AUTHN_LEVEL_PKT_PRIVACY 包括所有以前的身份验证级别,并对每个 RPC 调用的值进行加密。

 

可以使用 CoInitializeSecurity 的 pAuthList 参数中的 SOLE_AUTHENTICATION_LIST 结构为多个用户指定默认身份验证凭据。

以下代码示例演示如何更改身份验证凭据。

// Auth Identity structure
SEC_WINNT_AUTH_IDENTITY_W        authidentity;
SecureZeroMemory( &authidentity, sizeof(authidentity) );

authidentity.User = L"MyUser";
authidentity.UserLength = wcslen( authidentity.User );
authidentity.Domain = L"MyDomain ";
authidentity.DomainLength = wcslen( authidentity.Domain );
authidentity.Password = L"";
authidentity.PasswordLength = wcslen( authidentity.Password );
authidentity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;

SecureZeroMemory( authninfo, sizeof(SOLE_AUTHENTICATION_INFO)*2 );

// NTLM Settings
authninfo[0].dwAuthnSvc = RPC_C_AUTHN_WINNT;
authninfo[0].dwAuthzSvc = RPC_C_AUTHZ_NONE;
authninfo[0].pAuthInfo = &authidentity;

// Kerberos Settings
authninfo[1].dwAuthnSvc = RPC_C_AUTHN_GSS_KERBEROS ;
authninfo[1].dwAuthzSvc = RPC_C_AUTHZ_NONE;
authninfo[1].pAuthInfo = &authidentity;

SOLE_AUTHENTICATION_LIST    authentlist;

authentlist.cAuthInfo = 2;
authentlist.aAuthInfo = authninfo;

CoInitializeSecurity( 
  NULL, 
  -1, 
  NULL, 
  NULL, 
  RPC_C_AUTHN_LEVEL_CALL, 
  RPC_C_IMP_LEVEL_IMPERSONATE,
  &authentlist, 
  EOAC_NONE,
  NULL);

使用 C++ 更改默认模拟级别

COM 提供从系统注册表读取的默认安全级别。 但是,除非专门修改,否则注册表设置会将模拟级别设置得太低,导致 WMI 无法运行。 通常情况下,默认模拟级别为 RPC_C_IMP_LEVEL_IDENTIFY,但 WMI 至少需要 RPC_C_IMP_LEVEL_IMPERSONATE 才能与大多数提供程序一起运行。你可能会遇到需要设置更高级别模拟的情况。 有关详细信息,请参阅连接到远程计算机上的 WMI。 下表列出了不同级别的模拟。

Level 说明
RPC_C_IMP_LEVEL_DEFAULT 操作系统选择模拟级别。
RPC_C_IMP_LEVEL_ANONYMOUS 服务器可以模拟客户端,但模拟令牌不能用于任何内容。
RPC_C_IMP_LEVEL_IDENTIFY 服务器可以获取客户端的标识,并模拟客户端进行 ACL 检查。
RPC_C_IMP_LEVEL_IMPERSONATE 服务器可以跨一个计算机边界模拟客户端。
RPC_C_IMP_LEVEL_DELEGATE 服务器可以跨多个边界模拟客户端,并且可以代表客户端进行调用。