在非同步呼叫上設定安全性

非同步呼叫會造成嚴重的安全性風險,因為對 接收 的回呼可能不是原始應用程式或腳本的非同步呼叫的結果。 遠端連線的安全性是以用戶端與遠端電腦上的提供者之間的通訊加密為基礎。 在 C++ 中,您可以透過 呼叫 CoInitializeSecurity中的驗證層級參數來設定加密。 在腳本中,在 Moniker 連線或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\WBEMCIMOM\\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 指標。 此外,請勿在 WMI 釋放 pSink 接收指標之後釋放pStubSinkpSink之後釋放pStubSink會建立迴圈參考計數,其中接收和存根都會永久保留在記憶體中。 相反地,釋放指標的可能位置位於 IWbemObjectSink::SetStatus 呼叫中,由 WMI 發出以報告原始非同步呼叫已完成。

  7. 完成時,使用 對 Release () 的呼叫取消初始化 COM。

    下列程式碼範例示範如何在pUnsecApp指標上呼叫Release ()

    pUnsecApp->Release();
    

如需 CoInitializeSecurity 函式和參數的詳細資訊,請參閱 COM 檔。