Festlegen der Sicherheit für einen asynchronen Aufruf

Asynchrone Aufrufe stellen schwerwiegende Sicherheitsrisiken dar, weil ein Rückruf an die Senke möglicherweise nicht dem Ergebnis des asynchronen Aufrufs durch die ursprüngliche Anwendung oder das ursprüngliche Skript entspricht. Die Sicherheit in Remoteverbindungen basiert auf der Verschlüsselung der Kommunikation zwischen dem Client und dem Anbieter auf dem Remotecomputer. In C++ können Sie die Verschlüsselung über den Parameter für die Authentifizierungsebene im Aufruf von CoInitializeSecurity festlegen. Legen Sie bei der Skripterstellung den AuthenticationLevel in der Monikerverbindung oder für ein SWbemSecurity-Objekt fest. Weitere Informationen finden Sie unter Festlegen der Sicherheitsebene für Standardprozesse mit VBScript.

Die Sicherheitsrisiken für asynchrone Aufrufe sind darauf zurückzuführen, dass WMI die Authentifizierungsebene für einen Rückruf senkt, bis der Rückruf erfolgreich ist. Bei einem ausgehenden asynchronen Aufruf kann der Client die Authentifizierungsebene für die Verbindung mit WMI festlegen. WMI ruft die Sicherheitseinstellungen für den Clientaufruf ab und versucht den Rückruf mit derselben Authentifizierungsebene. Der Rückruf wird immer auf der Ebene RPC_C_AUTHN_LEVEL_PKT_PRIVACY initiiert. Wenn der Rückruf fehlschlägt, senkt WMI die Authentifizierungsebene auf eine Ebene, auf der der Rückruf erfolgreich durchgeführt werden kann, ggf. RPC_C_AUTHN_LEVEL_NONE. Im Kontext von Aufrufen innerhalb des lokalen Systems, bei denen nicht Kerberos als Authentifizierungsdienst dient, wird der Rückruf immer auf der Ebene RPC_C_AUTHN_LEVEL_NONE zurückgegeben.

Die Mindestauthentifizierungsebene ist RPC_C_AUTHN_LEVEL_PKT (wbemAuthenticationLevelPkt für die Skripterstellung). Sie können jedoch eine höhere Ebene angeben, z. B. RPC_C_AUTHN_LEVEL_PKT_PRIVACY (wbemAuthenticationLevelPktPrivacy). Es wird empfohlen, die Authentifizierungsebene in Clientanwendungen oder Skripts auf RPC_C_AUTHN_LEVEL_DEFAULT (wbemAuthenticationLevelDefault) festzulegen, wodurch die Authentifizierungsebene auf die vom Server angegebene Ebene ausgehandelt werden kann.

Der Registrierungswert HKEY_LOCAL_MACHINE\Software\Microsoft\WBEM\CIMOM\UnsecAppAccessControlDefault steuert, ob WMI bei Rückrufen auf eine akzeptable Authentifizierungsebene überprüft. Dies ist der einzige Mechanismus zum Schutz der Senkensicherheit für asynchrone Aufrufe in Skripts oder Visual Basic. Standardmäßig ist dieser Registrierungsschlüssel auf 0 (null) festgelegt. Wenn der Registrierungsschlüssel null ist, werden Authentifizierungsebenen durch WMI nicht verifiziert. Um asynchrone Aufrufe bei der Skripterstellung zu schützen, legen Sie den Registrierungsschlüssel auf 1 (eins) fest. C++-Clients können IWbemUnsecuredApartment::CreateSinkStub aufrufen, um den Zugriff auf die Senke zu steuern. Der Wert wird standardmäßig an einer beliebigen Stelle erstellt.

Die folgenden Themen enthalten Beispiele für das Festlegen der Sicherheit für asynchrone Aufrufe:

Festlegen der Sicherheit für asynchrone Aufrufe in C++

Die IWbemUnsecuredApartment::CreateSinkStub-Methode ähnelt der IUnsecuredApartment::CreateObjectStub-Methode und erstellt eine Senke in einem separaten Prozess, „Unsecapp.exe“, um Rückrufe zu empfangen. Die CreateSinkStub-Methode verfügt jedoch über einen dwFlag-Parameter, der angibt, wie der separate Prozess die Zugriffssteuerung behandelt.

Der dwFlag-Parameter gibt eine der folgenden Aktionen für „Unsecapp.exe“ an:

  • Verwenden der Registrierungsschlüsseleinstellung, um zu bestimmen, ob der Zugriff überprüft werden soll.
  • Ignorieren des Registrierungsschlüssels und grundsätzliches Überprüfen des Zugriffs.
  • Ignorieren des Registrierungsschlüssels und kein Überprüfen des Zugriffs.

Für das Codebeispiel in diesem Thema ist die folgende #include-Anweisung für eine ordnungsgemäße Kompilierung erforderlich.

#include <wbemidl.h>

Im folgenden Verfahren wird beschrieben, wie Sie einen asynchronen Aufruf mit IWbemUnsecuredApartment ausführen.

So führen Sie einen asynchronen Aufruf mit „IWbemUnsecuredApartment“ aus

  1. Erstellen Sie einen dedizierten Prozess durch Aufrufen von CoCreateInstance.

    Im folgenden Codebeispiel wird CoCreateInstance aufgerufen, um einen dedizierten Prozess zu erstellen.

    CLSID                    CLSID_WbemUnsecuredApartment;
    IWbemUnsecuredApartment* pUnsecApp = NULL;
    
    CoCreateInstance(CLSID_WbemUnsecuredApartment, 
                     NULL, 
                     CLSCTX_LOCAL_SERVER, 
                     IID_IWbemUnsecuredApartment, 
                     (void**)&pUnsecApp);
    
  2. Instanziieren Sie das Senkenobjekt.

    Im folgenden Codebeispiel wird ein neues Senkenobjekt erstellt.

    CMySink* pSink = new CMySink;
    pSink->AddRef();
    
  3. Erstellen Sie einen Stub für den neuen Code.

    Ein Stub ist eine Wrapperfunktion, die von der Senke erzeugt wird.

    Im folgenden Codebeispiel wird ein Stub für die Senke erstellt.

    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. Geben Sie den Senkenobjektzeiger frei.

    Sie können den Objektzeiger freigeben, da der Stub jetzt den Zeiger besitzt.

    Im folgenden Codebeispiel wird der Objektzeiger freigegeben.

    pSink->Release();
    
  5. Verwenden Sie den Stub in jedem asynchronen Aufruf.

    Wenn Sie mit dem Aufruf fertig sind, geben Sie die lokale Verweisanzahl frei.

    Im folgenden Codebeispiel wird der Stub in einem asynchronen Aufruf verwendet.

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

    Manchmal müssen Sie möglicherweise einen asynchronen Aufruf abbrechen, nachdem Sie ihn gestartet haben. Wenn Sie den Anruf abbrechen müssen, brechen Sie ihn mit demselben Zeiger ab, mit dem der Aufruf ursprünglich getätigt wurde.

    Im folgenden Codebeispiel wird beschrieben, wie Sie einen asynchronen Aufruf abbrechen.

    pServices->CancelAsyncCall(pStubSink);
    
  6. Geben Sie die lokale Verweisanzahl frei, wenn Sie mit dem asynchronen Aufruf fertig sind.

    Geben Sie den Zeiger pStubSink erst frei, nachdem Sie sich vergewissert haben, dass der asynchrone Aufruf nicht abgebrochen werden muss. Darüber hinaus dürfen Sie pStubSink nicht freigeben, nachdem WMI den Senkenzeiger pSink freigegeben hat. Die Freigabe von pStubSink nach pSink erzeugt eine Zirkelverweisanzahl, bei der sowohl die Senke als auch der Stub für immer im Arbeitsspeicher verbleiben. Ein möglicher Ort für die Freigabe des Zeigers ist stattdessen der Aufruf IWbemObjectSink::SetStatus, der von WMI ausgeführt wird, um zu melden, dass der ursprüngliche asynchrone Aufruf abgeschlossen ist.

  7. Nach Fertigstellung heben Sie die Initialisierung von COM mit einem Aufruf von Release() auf.

    Im folgenden Codebeispiel wird veranschaulicht, wie Release() für den pUnsecApp-Zeiger aufgerufen wird.

    pUnsecApp->Release();
    

Weitere Informationen zur CoInitializeSecurity-Funktion und zu den zugehörigen Parametern finden Sie in der COM-Dokumentation.