비동기 호출에서 보안 설정

싱크에 대한 콜백이 원래 애플리케이션 또는 스크립트의 비동기 호출에 따른 결과가 아닐 수 있으므로 비동기 호출은 심각한 보안 위험을 초래합니다. 원격 연결의 보안은 원격 컴퓨터에서 클라이언트와 공급자 간의 통신 암호화를 기반으로 합니다. C++에서는 CoInitializeSecurity 호출에서 인증 수준 매개 변수를 통해 암호화를 설정할 수 있습니다. 스크립팅에서 모니커 연결 또는 SWbemSecurity 개체에서 AuthenticationLevel을 설정합니다. 자세한 내용은 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에서 수행한 비동기 호출에 대한 싱크 보안을 보호하는 유일한 메커니즘입니다. 기본적으로 이 레지스트리 키는 0으로 설정됩니다. 레지스트리 키가 0이면 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 포인터를 릴리스해야 합니다. 또한 WMI가 pSink 싱크 포인터를 릴리스한 후에는 pStubSink를 릴리스하지 마세요. pSink 후에 pStubSink를 릴리스하면 싱크와 스텁이 메모리에 영원히 유지되는 순환 참조 수가 생성됩니다. 대신 포인터를 릴리스할 수 있는 위치는 원래 비동기 호출이 완료되었음을 보고하기 위해 WMI에서 수행한 IWbemObjectSink::SetStatus 호출에 있습니다.

  7. 완료되면 Release()를 호출하여 COM을 초기화하지 않습니다.

    다음 코드 예제에서는 pUnsecApp 포인터에서 Release()를 호출하는 방법을 보여줍니다.

    pUnsecApp->Release();
    

CoInitializeSecurity 함수 및 매개 변수에 관한 자세한 내용은 COM 설명서를 참조하세요.