Partilhar via


Definindo a segurança em uma chamada assíncrona

As chamadas assíncronas apresentam sérios riscos de segurança porque uma chamada de retorno para o coletor de pode não ser resultado da chamada assíncrona por parte do aplicativo ou script original. A segurança em conexões remotas é baseada na criptografia da comunicação entre o cliente e o provedor no computador remoto. Em C++, você pode definir a criptografia por meio do parâmetro de nível de autenticação na chamada para CoInitializeSecurity. Em scripts, defina o AuthenticationLevel na conexão de moniker ou em um objeto SWbemSecurity. Para obter mais informações, consulte Definindo o nível de segurança padrão do processo usando o VBScript.

Os riscos de segurança para chamadas assíncronas existem porque o WMI reduz o nível de autenticação num retorno de chamada até que o retorno de chamada seja bem-sucedido. Em uma chamada assíncrona de saída, o cliente pode definir o nível de autenticação na conexão com WMI. O WMI recupera as configurações de segurança na chamada do cliente e tenta ligar de volta com o mesmo nível de autenticação. A chamada de retorno é sempre iniciada no nível RPC_C_AUTHN_LEVEL_PKT_PRIVACY. Se o retorno de chamada falhar, o WMI reduzirá o nível de autenticação para um nível em que o retorno de chamada possa ser bem-sucedido, se necessário, para RPC_C_AUTHN_LEVEL_NONE. No contexto de chamadas dentro do sistema local onde o serviço de autenticação não é Kerberos, o retorno de chamada ocorre sempre em RPC_C_AUTHN_LEVEL_NONE.

O nível mínimo de autenticação é RPC_C_AUTHN_LEVEL_PKT (wbemAuthenticationLevelPktpara scripting). No entanto, você pode especificar um nível superior, como RPC_C_AUTHN_LEVEL_PKT_PRIVACY (wbemAuthenticationLevelPktPrivacy). É recomendável que os aplicativos cliente ou scripts definam o nível de autenticação como RPC_C_AUTHN_LEVEL_DEFAULT (wbemAuthenticationLevelDefault), o que permite que o nível de autenticação seja negociado para o nível especificado pelo servidor.

O HKEY_LOCAL_MACHINE\Software\Microsoft\WBEM\CIMOM\UnsecAppAccessControlDefault controla se o WMI verifica a existência de um nível de autenticação aceitável em chamadas de retorno. Este é o único mecanismo para proteger a segurança do coletor para chamadas assíncronas feitas em scripts ou Visual Basic. Por padrão, essa chave do Registro é definida como zero. Se a chave do Registro for zero, o WMI não verificará os níveis de autenticação. Para proteger chamadas assíncronas em scripts, defina a chave do Registro como 1. Os clientes C++ podem chamar IWbemUnsecuredApartment::CreateSinkStub para controlar o acesso ao coletor. O valor é criado em qualquer lugar por padrão.

Os tópicos a seguir fornecem exemplos de configuração de segurança de chamada assíncrona:

Definindo a segurança de chamada assíncrona em C++

O método IWbemUnsecuredApartment::CreateSinkStub é semelhante ao método IUnsecuredApartment::CreateObjectStub e cria um coletor em um processo separado, Unsecapp.exe, para receber retornos de chamada. No entanto, o método CreateSinkStub tem um parâmetro dwFlagque especifica como o processo separado manipula o controle de acesso.

O parâmetro dwFlag especifica uma das seguintes ações para Unsecapp.exe:

  • Use a configuração da chave do Registro para determinar se o acesso deve ou não ser verificado.
  • Ignore a chave do Registro e sempre verifique o acesso.
  • Ignore a chave do Registro e nunca verifique o acesso.

O exemplo de código neste tópico requer a seguinte instrução #include para compilar corretamente.

#include <wbemidl.h>

O procedimento a seguir descreve como executar uma chamada assíncrona com IWbemUnsecuredApartment.

Para executar uma chamada assíncrona com IWbemUnsecuredApartment

  1. Crie um processo dedicado com uma chamada para CoCreateInstance.

    O exemplo de código a seguir chama CoCreateInstance para criar um processo dedicado.

    CLSID                    CLSID_WbemUnsecuredApartment;
    IWbemUnsecuredApartment* pUnsecApp = NULL;
    
    CoCreateInstance(CLSID_WbemUnsecuredApartment, 
                     NULL, 
                     CLSCTX_LOCAL_SERVER, 
                     IID_IWbemUnsecuredApartment, 
                     (void**)&pUnsecApp);
    
  2. Instanciar o objeto do sumidouro.

    O exemplo de código a seguir cria um novo objeto coletor.

    CMySink* pSink = new CMySink;
    pSink->AddRef();
    
  3. Crie um esboço para a pia.

    Um esboço é uma função de encapsulamento produzida a partir do sink.

    O exemplo de código a seguir cria um stub para o coletor.

    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. Liberte o ponteiro do objeto sumidouro.

    Você pode liberar o ponteiro de objeto porque o stub agora possui o ponteiro.

    O exemplo de código abaixo libera o ponteiro do objeto.

    pSink->Release();
    
  5. Use o stub em qualquer chamada assíncrona.

    Quando terminar a chamada, liberte a contagem de referência local.

    O exemplo de código a seguir usa o stub em uma chamada assíncrona.

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

    Às vezes, você pode ter que cancelar uma chamada assíncrona depois de fazer a chamada. Se precisares cancelar a chamada, cancela a chamada com o mesmo ponteiro que fez a chamada originalmente.

    O exemplo de código a seguir descreve como cancelar uma chamada assíncrona.

    pServices->CancelAsyncCall(pStubSink);
    
  6. Liberte a contagem de referência local quando terminar do uso da chamada assíncrona.

    Certifique-se de liberar o ponteiro pStubSink somente depois de confirmar que a chamada assíncrona não deve ser cancelada. Além disso, não solte pStubSink depois que o WMI liberar o ponteiro de sink pSink. Liberar pStubSink após pSink cria uma contagem de referência circular na qual tanto o recetor quanto o stub permanecem na memória para sempre. Em vez disso, um possível local para liberar o ponteiro está na chamada IWbemObjectSink::SetStatus, feita pelo WMI para informar que a chamada assíncrona original foi concluída.

  7. Quando terminar, desinicialize o COM com uma chamada para Release().

    O exemplo de código a seguir mostra como chamar Release() no ponteiro pUnsecApp.

    pUnsecApp->Release();
    

Para obter mais informações sobre a função CoInitializeSecurity e parâmetros, consulte a documentação do COM.