Mengatur Keamanan pada Panggilan Asinkron

Panggilan asinkron menghadirkan risiko keamanan yang serius karena panggilan balik ke sink mungkin bukan akibat panggilan asinkron oleh aplikasi atau skrip asli. Keamanan dalam koneksi jarak jauh didasarkan pada enkripsi komunikasi antara klien dan penyedia di komputer jarak jauh. Di C++ Anda dapat mengatur enkripsi melalui parameter tingkat autentikasi dalam panggilan ke CoInitializeSecurity. Dalam pembuatan skrip, atur AuthenticationLevel di koneksi moniker atau pada objek SWbemSecurity . Untuk informasi selengkapnya, lihat Mengatur Tingkat Keamanan Proses Default Menggunakan VBScript.

Risiko keamanan untuk panggilan asinkron ada karena WMI menurunkan tingkat autentikasi pada panggilan balik hingga panggilan balik berhasil. Pada panggilan asinkron keluar, klien dapat mengatur tingkat autentikasi pada koneksi ke WMI. WMI mengambil pengaturan keamanan pada panggilan klien dan mencoba memanggil kembali dengan tingkat autentikasi yang sama. Panggilan balik selalu dimulai pada tingkat RPC_C_AUTHN_LEVEL_PKT_PRIVACY . Jika panggilan balik gagal, WMI menurunkan tingkat autentikasi ke tingkat di mana panggilan balik dapat berhasil, jika perlu, untuk RPC_C_AUTHN_LEVEL_NONE. Dalam konteks panggilan dalam sistem lokal di mana layanan autentikasi bukan Kerberos, panggilan balik selalu dikembalikan pada RPC_C_AUTHN_LEVEL_NONE.

Tingkat autentikasi minimum adalah RPC_C_AUTHN_LEVEL_PKT (wbemAuthenticationLevelPktuntuk pembuatan skrip). Namun, Anda dapat menentukan tingkat yang lebih tinggi, seperti RPC_C_AUTHN_LEVEL_PKT_PRIVACY (wbemAuthenticationLevelPktPrivacy). Disarankan agar aplikasi atau skrip klien mengatur tingkat autentikasi ke RPC_C_AUTHN_LEVEL_DEFAULT (wbemAuthenticationLevelDefault) yang memungkinkan tingkat autentikasi dinegosiasikan ke tingkat yang ditentukan oleh server.

Nilai registri HKEY_LOCAL_MACHINE\Software\Microsoft\WBEM\CIMOM\UnsecAppAccessControlDefault mengontrol apakah WMI memeriksa tingkat autentikasi yang dapat diterima dalam panggilan balik. Ini adalah satu-satunya mekanisme untuk melindungi keamanan sink untuk panggilan asinkron yang dilakukan dalam pembuatan skrip atau Visual Basic. Secara default, kunci registri ini diatur ke nol. Jika kunci registri nol, maka WMI tidak memverifikasi tingkat autentikasi. Untuk mengamankan panggilan asinkron dalam pembuatan skrip, atur kunci registri ke 1. Klien C++ dapat memanggil IWbemUnsecuredApartment::CreateSinkStub untuk mengontrol akses ke sink. Nilai dibuat di mana saja secara default.

Topik berikut memberikan contoh pengaturan keamanan panggilan asinkron:

Mengatur Keamanan Panggilan Asinkron di C++

Metode IWbemUnsecuredApartment::CreateSinkStub mirip dengan metode IUnsecuredApartment::CreateObjectStub dan membuat sink dalam proses terpisah, Unsecapp.exe, untuk menerima panggilan balik. Namun, metode CreateSinkStub memiliki parameter dwFlagyang menentukan bagaimana proses terpisah menangani kontrol akses.

Parameter dwFlag menentukan salah satu tindakan berikut untuk Unsecapp.exe:

  • Gunakan pengaturan kunci registri untuk menentukan apakah akan memeriksa akses atau tidak.
  • Abaikan kunci registri dan selalu periksa akses.
  • Abaikan kunci registri dan jangan pernah periksa akses.

Contoh kode dalam topik ini memerlukan pernyataan #include berikut untuk mengkompilasi dengan benar.

#include <wbemidl.h>

Prosedur berikut menjelaskan cara melakukan panggilan asinkron dengan IWbemUnsecuredApartment.

Untuk melakukan panggilan asinkron dengan IWbemUnsecuredApartment

  1. Buat proses khusus dengan panggilan ke CoCreateInstance.

    Contoh kode berikut memanggil CoCreateInstance untuk membuat proses khusus.

    CLSID                    CLSID_WbemUnsecuredApartment;
    IWbemUnsecuredApartment* pUnsecApp = NULL;
    
    CoCreateInstance(CLSID_WbemUnsecuredApartment, 
                     NULL, 
                     CLSCTX_LOCAL_SERVER, 
                     IID_IWbemUnsecuredApartment, 
                     (void**)&pUnsecApp);
    
  2. Buat instans objek sink.

    Contoh kode berikut membuat objek sink baru.

    CMySink* pSink = new CMySink;
    pSink->AddRef();
    
  3. Buat stub untuk sink.

    Stub adalah fungsi pembungkus yang dihasilkan dari sink.

    Contoh kode berikut membuat stub untuk sink.

    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. Lepaskan penunjuk objek sink.

    Anda dapat melepaskan penunjuk objek karena stub sekarang memiliki pointer.

    Contoh kode berikut merilis penunjuk objek.

    pSink->Release();
    
  5. Gunakan stub dalam panggilan asinkron apa pun.

    Setelah selesai dengan panggilan, rilis jumlah referensi lokal.

    Contoh kode berikut menggunakan stub dalam panggilan asinkron.

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

    Terkadang Anda mungkin harus membatalkan panggilan asinkron setelah melakukan panggilan. Jika Anda perlu membatalkan panggilan, batalkan panggilan dengan pointer yang sama yang awalnya melakukan panggilan.

    Contoh kode berikut menjelaskan cara membatalkan panggilan asinkron.

    pServices->CancelAsyncCall(pStubSink);
    
  6. Rilis jumlah referensi lokal saat Anda selesai menggunakan panggilan asinkron.

    Pastikan untuk merilis pointer pStubSink hanya setelah Anda mengonfirmasi bahwa panggilan asinkron tidak harus dibatalkan. Selanjutnya, jangan rilis pStubSink setelah WMI merilis pointer sink pSink . Merilis pStubSink setelah pSink membuat jumlah referensi melingkar di mana sink dan stub tetap dalam memori selamanya. Sebagai gantinya, lokasi yang mungkin untuk merilis pointer ada di panggilan IWbemObjectSink::SetStatus , yang dibuat oleh WMI untuk melaporkan bahwa panggilan asinkron asli selesai.

  7. Setelah selesai, batalkan menginisialisasi COM dengan panggilan ke Release().

    Contoh kode berikut menunjukkan cara memanggil Release() pada pointer pUnsecApp .

    pUnsecApp->Release();
    

Untuk informasi selengkapnya tentang fungsi dan parameter CoInitializeSecurity , lihat dokumentasi COM .