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

Асинхронные вызовы представляют серьезные риски безопасности, так как обратный вызов приемника может не быть результатом асинхронного вызова исходного приложения или скрипта. Безопасность в удаленных подключениях основана на шифровании связи между клиентом и поставщиком на удаленном компьютере. В 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 (wbemAuthenticationLevelPktfor scripting). Однако можно указать более высокий уровень, например RPC_C_AUTHN_LEVEL_PKT_PRIVACY (wbemAuthenticationLevelPktPrivacy). Рекомендуется, чтобы клиентские приложения или скрипты устанавливали уровень проверки подлинности на RPC_C_AUTHN_LEVEL_DEFAULT (wbemAuthenticationLevelDefault), что позволяет согласовывать уровень проверки подлинности с уровнем, указанным сервером.

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

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

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

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

Параметр 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 .