Ustawianie zabezpieczeń w wywołaniu asynchronicznym
Wywołania asynchroniczne stanowią poważne zagrożenia bezpieczeństwa, ponieważ wywołanie zwrotne do ujścia może nie być wynikiem asynchronicznego wywołania przez oryginalną aplikację lub skrypt. Zabezpieczenia w połączeniach zdalnych są oparte na szyfrowaniu komunikacji między klientem a dostawcą na komputerze zdalnym. W języku C++ można ustawić szyfrowanie za pomocą parametru poziomu uwierzytelniania w wywołaniu CoInitializeSecurity. W skrypcie ustaw AuthenticationLevel w połączeniu z moniker lub na obiekcie SWbemSecurity. Aby uzyskać więcej informacji, zobacz Ustawianie domyślnego poziomu zabezpieczeń procesu przy użyciu języka VBScript.
Istnieją zagrożenia bezpieczeństwa dla wywołań asynchronicznych, ponieważ usługa WMI obniża poziom uwierzytelniania w wywołaniu zwrotnym, dopóki wywołanie zwrotne nie powiedzie się. W przypadku wychodzącego wywołania asynchronicznego klient może ustawić poziom uwierzytelniania na połączeniu z usługą WMI. Usługa WMI pobiera ustawienia zabezpieczeń wywołania klienta i próbuje wywołać je z powrotem przy użyciu tego samego poziomu uwierzytelniania. Wywołanie zwrotne jest zawsze inicjowane na poziomie RPC_C_AUTHN_LEVEL_PKT_PRIVACY. Jeśli wywołanie zwrotne zakończy się niepowodzeniem, usługa WMI obniży poziom uwierzytelniania, aby wywołanie zwrotne mogło się udać, w razie potrzeby, do RPC_C_AUTHN_LEVEL_NONE. W kontekście wywołań w systemie lokalnym, w którym usługa uwierzytelniania nie jest Kerberos, wywołanie zwrotne zawsze jest zwracane w RPC_C_AUTHN_LEVEL_NONE.
Minimalny poziom uwierzytelniania to RPC_C_AUTHN_LEVEL_PKT (wbemAuthenticationLevelna potrzeby skryptów). Można jednak określić wyższy poziom, na przykład RPC_C_AUTHN_LEVEL_PKT_PRIVACY (wbemAuthenticationLevelPktPrywatność). Zaleca się, aby aplikacje klienckie lub skrypty ustawiały poziom uwierzytelniania na RPC_C_AUTHN_LEVEL_DEFAULT (wbemAuthenticationLevelDefault), co umożliwia negocjowanie poziomu uwierzytelniania na poziomie określonym przez serwer.
HKEY_LOCAL_MACHINE\Software\Microsoft\WBEM\CIMOM\UnsecAppAccessControlDefault wartość rejestru określa, czy usługa WMI sprawdza akceptowalny poziom uwierzytelniania w wywołaniach zwrotnych. Jest to jedyny mechanizm ochrony zabezpieczeń ujścia dla wywołań asynchronicznych wykonanych w skryptach lub Visual Basic. Domyślnie ten klucz rejestru jest ustawiony na zero. Jeśli klucz rejestru ma wartość zero, usługa WMI nie weryfikuje poziomów uwierzytelniania. Aby zabezpieczyć wywołania asynchroniczne w skryptach, ustaw klucz rejestru na 1. Klienci języka C++ mogą wywoływać IWbemUnsecuredApartment::CreateSinkStub w celu kontrolowania dostępu do ujścia. Wartość jest tworzona w dowolnym miejscu domyślnie.
Poniższe tematy zawierają przykłady ustawiania asynchronicznych zabezpieczeń wywołań:
- ustawianie zabezpieczeń w wywołaniu asynchronicznym w języku VBScript
- Ustawianie asynchronicznych zabezpieczeń wywołań w języku C++
Ustawianie asynchronicznych zabezpieczeń wywołań w języku C++
Metoda IWbemUnsecuredApartment::CreateSinkStub jest podobna do metody IUnsecuredApartment::CreateObjectStub i tworzy ujście w osobnym procesie, Unsecapp.exe, aby odbierać wywołania zwrotne. Jednak metoda CreateSinkStub ma parametr dwFlagokreślający sposób obsługi kontroli dostępu przez oddzielny proces.
Parametr dwFlag określa jedną z następujących akcji dla Unsecapp.exe:
- Użyj ustawienia klucza rejestru, aby określić, czy chcesz sprawdzić dostęp.
- Ignoruj klucz rejestru i zawsze sprawdzaj dostęp.
- Ignoruj klucz rejestru i nigdy nie sprawdzaj dostępu.
Przykład kodu w tym temacie wymaga następującej instrukcji #include w celu poprawnego skompilowania.
#include <wbemidl.h>
Poniższa procedura opisuje, jak wykonać wywołanie asynchroniczne za pomocą IWbemUnsecuredApartment.
Aby wykonać wywołanie asynchroniczne za pomocą IWbemUnsecuredApartment
Utwórz dedykowany proces za pomocą wywołania CoCreateInstance.
Poniższy przykład kodu wywołuje CoCreateInstance w celu utworzenia dedykowanego procesu.
CLSID CLSID_WbemUnsecuredApartment; IWbemUnsecuredApartment* pUnsecApp = NULL; CoCreateInstance(CLSID_WbemUnsecuredApartment, NULL, CLSCTX_LOCAL_SERVER, IID_IWbemUnsecuredApartment, (void**)&pUnsecApp);
Utwórz wystąpienie obiektu ujścia.
Poniższy przykład kodu tworzy nowy obiekt ujścia.
CMySink* pSink = new CMySink; pSink->AddRef();
Utwórz szablon dla umywalki.
Stub jest funkcją opakowującą utworzoną z docelowego interfejsu.
Poniższy przykład kodu tworzy szkielet dla odbiornika.
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);
Zwolnij wskaźnik obiektu docelowego.
Wskaźnik obiektu można zwolnić, ponieważ element wycinkowy jest teraz właścicielem wskaźnika.
Poniższy przykład kodu zwalnia wskaźnik obiektu.
pSink->Release();
Użyj stuby w dowolnym wywołaniu asynchronicznym.
Po zakończeniu połączenia zwolnij liczbę lokalnych odwołań.
W poniższym przykładzie kodu użyto szablonu w wywołaniu asynchronicznym.
// pServices is an IWbemServices* object pServices->CreateInstanceEnumAsync(strClassName, 0, NULL, pStubSink);
Czasami może być konieczne anulowanie połączenia asynchronicznego, gdy już zostało ono zainicjowane. Jeśli musisz anulować połączenie, anuluj połączenie za pomocą tego samego wskaźnika, który pierwotnie nawiązał połączenie.
W poniższym przykładzie kodu opisano sposób anulowania wywołania asynchronicznego.
pServices->CancelAsyncCall(pStubSink);
Zwolnij licznik odwołań lokalnych po zakończeniu korzystania z wywołania asynchronicznego.
Pamiętaj, aby zwolnić wskaźnik pStubSink dopiero po potwierdzeniu, że połączenie asynchroniczne nie musi zostać anulowane. Ponadto nie zwalniaj pStubSink po tym, jak WMI zwalnia wskaźnik odbiornika pSink. Zwalnianie pStubSink po pSink powoduje cykliczne zliczanie odwołań, w wyniku którego zarówno sink, jak i stub pozostają w pamięci na stałe. Zamiast tego możliwe miejsce zwolnienia wskaźnika jest w wywołaniu IWbemObjectSink::SetStatus, wykonane przez usługę WMI w celu zgłoszenia, że oryginalne wywołanie asynchroniczne zostało ukończone.
Po zakończeniu, odinicjuj interfejs COM za pomocą wywołania metody Release().
Poniższy przykład kodu pokazuje, jak wywołać Release() na wskaźniku pUnsecApp.
pUnsecApp->Release();
Aby uzyskać więcej informacji na temat funkcji i parametrów CoInitializeSecurity, zobacz dokumentację COM.