Поделиться через


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

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