Настройка безопасности при асинхронном вызове

Асинхронные вызовы представляют серьезную угрозу безопасности, так как обратный вызов в приемник может не быть результатом асинхронного вызова исходного приложения или скрипта. Безопасность удаленных подключений основана на шифровании обмена данными между клиентом и поставщиком на удаленном компьютере. В C++ можно задать шифрование с помощью параметра уровня проверки подлинности в вызове CoInitializeSecurity. В скрипте задайте AuthenticationLevel в соединении с моникером или в объекте SWbemSecurity . Дополнительные сведения см. в разделе Настройка уровня безопасности процесса по умолчанию с помощью VBScript.

Риски безопасности для асинхронных вызовов существуют из-за того, что WMI снижает уровень проверки подлинности при обратном вызове до тех пор, пока обратный вызов не будет выполнен успешно. При исходящем асинхронном вызове клиент может задать уровень проверки подлинности при подключении к WMI. WMI извлекает параметры безопасности при вызове клиента и пытается выполнить обратный вызов с тем же уровнем проверки подлинности. Обратный вызов всегда инициируется на уровне RPC_C_AUTHN_LEVEL_PKT_PRIVACY . Если обратный вызов завершается сбоем, WMI понижает уровень проверки подлинности до уровня, на котором обратный вызов может быть выполнен, если это необходимо, чтобы RPC_C_AUTHN_LEVEL_NONE. В контексте вызовов в локальной системе, где служба проверки подлинности не является Kerberos, обратный вызов всегда возвращается по RPC_C_AUTHN_LEVEL_NONE.

Минимальный уровень проверки подлинности — RPC_C_AUTHN_LEVEL_PKT (wbemAuthenticationLevelPktдля создания скриптов). Однако можно указать более высокий уровень, например RPC_C_AUTHN_LEVEL_PKT_PRIVACY (wbemAuthenticationLevelPktPrivacy). Рекомендуется, чтобы клиентские приложения или сценарии устанавливали уровень проверки подлинности RPC_C_AUTHN_LEVEL_DEFAULT (wbemAuthenticationLevelDefault), что позволяет согласовывать уровень проверки подлинности с уровнем, заданным сервером.

Значение реестра HKEY_LOCAL_MACHINE\Software\Microsoft\WBEM\CIMOM\UnsecAppAccessControlDefault определяет, проверяет ли WMI приемлемый уровень проверки подлинности в обратных вызовах. Это единственный механизм защиты приемника для асинхронных вызовов, выполненных в скриптах или Visual Basic. По умолчанию этот раздел реестра имеет нулевое значение. Если раздел реестра равен нулю, WMI не проверяет уровни проверки подлинности. Чтобы защитить асинхронные вызовы в скриптах, задайте для раздела реестра значение 1. Клиенты C++ могут вызывать IWbemUnsecuredApartment::CreateSinkStub для управления доступом к приемнику. Значение по умолчанию создается в любом месте.

В следующих разделах приведены примеры настройки асинхронной безопасности вызовов.

Настройка асинхронной безопасности вызовов в C++

Метод IWbemUnsecuredApartment::CreateSinkStub аналогичен методу IUnsecuredApartment::CreateObjectStub и создает приемник в отдельном процессе, Unsecapp.exe, для получения обратных вызовов. Однако метод CreateSinkStub имеет параметр dwFlag, указывающий, как отдельный процесс обрабатывает управление доступом.

Параметр dwFlag указывает одно из следующих действий для Unsecapp.exe:

  • Используйте параметр раздела реестра, чтобы определить, следует ли проверка доступ.
  • Игнорируйте раздел реестра и всегда проверка доступ.
  • Игнорируйте раздел реестра и никогда не проверка доступ.

Для правильной компиляции в примере кода в этом разделе требуется следующая инструкция #include.

#include <wbemidl.h>

В следующей процедуре описывается выполнение асинхронного вызова с помощью IWbemUnsecuredApartment.

Выполнение асинхронного вызова с помощью IWbemUnsecuredApartment

  1. Создайте выделенный процесс с вызовом CoCreateInstance.

    Следующий пример кода вызывает CoCreateInstance для создания выделенного процесса.

    CLSID                    CLSID_WbemUnsecuredApartment;
    IWbemUnsecuredApartment* pUnsecApp = NULL;
    
    CoCreateInstance(CLSID_WbemUnsecuredApartment, 
                     NULL, 
                     CLSCTX_LOCAL_SERVER, 
                     IID_IWbemUnsecuredApartment, 
                     (void**)&pUnsecApp);
    
  2. Создайте экземпляр объекта приемника.

    В следующем примере кода создается новый объект приемника.

    CMySink* pSink = new CMySink;
    pSink->AddRef();
    
  3. Создайте заглушку для приемника.

    Заглушка — это функция-оболочка, созданная из приемника.

    В следующем примере кода создается заглушка для приемника.

    LPCWSTR          wszReserved = NULL;           
    IWbemObjectSink* pStubSink   = NULL;
    IUnknown*        pStubUnk    = NULL; 
    
    pUnsecApp->CreateSinkStub(pSink,
                              WBEM_FLAG_UNSECAPP_CHECK_ACCESS,  //Authenticate callbacks regardless of registry key
                              wszReserved,
                              &pStubSink);
    
  4. Отпустите указатель на объект приемника.

    Вы можете освободить указатель объекта, так как заглушка теперь владеет указателем.

    В следующем примере кода освобождается указатель объекта.

    pSink->Release();
    
  5. Используйте заглушку в любом асинхронном вызове.

    Завершив вызов, отпустите число локальных ссылок.

    В следующем примере кода используется заглушка в асинхронном вызове.

    // pServices is an IWbemServices* object
    pServices->CreateInstanceEnumAsync(strClassName, 0, NULL, pStubSink);
    

    Иногда после выполнения вызова может потребоваться отменить асинхронный вызов. Если необходимо отменить вызов, отмените вызов с помощью того же указателя, который был выполнен изначально.

    В следующем примере кода описывается отмена асинхронного вызова.

    pServices->CancelAsyncCall(pStubSink);
    
  6. Освободит число локальных ссылок после завершения асинхронного вызова.

    Отпустите указатель pStubSink только после подтверждения отмены асинхронного вызова. Кроме того, не отпускайте pStubSink после того, как WMI освобождает указатель приемника pSink . При освобождении pStubSink после pSink создается циклическое число ссылок, в котором приемник и заглушка остаются в памяти навсегда. Вместо этого возможное расположение для освобождения указателя находится в вызове IWbemObjectSink::SetStatus , выполненном WMI, чтобы сообщить о завершении исходного асинхронного вызова.

  7. По завершении не инициализируйте COM с помощью вызова Release().

    В следующем примере кода показано, как вызвать Release() в указателе pUnsecApp .

    pUnsecApp->Release();
    

Дополнительные сведения о функции и параметрах CoInitializeSecurity см. в документации по COM .