Menyamar menjadi Klien
Ketika aplikasi pengguna meminta data dari objek pada sistem melalui penyedia WMI, peniruan identitas berarti penyedia akan menampilkan kredensial yang mewakili tingkat keamanan klien, bukan penyedia. Peniruan mencegah klien mendapatkan akses tidak sah ke informasi pada sistem.
Bagian berikut dibahas dalam topik ini:
- Mendaftarkan Penyedia untuk Peniruan Identitas
- Mengatur Tingkat Peniruan Dalam Penyedia
- Mempertahankan Tingkat Keamanan di Penyedia
- Menangani Pesan Akses Ditolak di Penyedia
- Melaporkan Contoh Parsial
- Melaporkan Enumerasi Parsial
- Memperbaiki Kode Akses Ditolak
- Topik terkait
WMI biasanya berjalan sebagai layanan administratif pada tingkat keamanan tinggi, menggunakan konteks keamanan LocalServer. Menggunakan layanan administratif memberi WMI sarana untuk mengakses informasi istimewa. Saat memanggil penyedia untuk informasi, WMI meneruskan pengidentifikasi keamanan (SID) ke penyedia, memungkinkan penyedia untuk mengakses informasi pada tingkat keamanan tinggi yang sama.
Selama proses peluncuran aplikasi WMI, sistem operasi Windows memberi aplikasi WMI konteks keamanan pengguna yang memulai proses. Konteks keamanan pengguna biasanya merupakan tingkat keamanan yang lebih rendah daripada LocalServer, sehingga pengguna mungkin tidak memiliki izin untuk mengakses semua informasi yang tersedia untuk WMI. Ketika aplikasi pengguna meminta informasi dinamis, WMI meneruskan SID pengguna ke penyedia yang sesuai. Jika ditulis dengan tepat, penyedia mencoba mengakses informasi dengan SID pengguna, bukan SID penyedia.
Agar penyedia berhasil meniru aplikasi klien, aplikasi dan penyedia klien harus memenuhi kriteria berikut:
- Aplikasi klien harus memanggil WMI dengan level keamanan koneksi COM RPC_C_IMP_LEVEL_IMPERSONATE atau RPC_C_IMP_LEVEL_DELEGATE. Untuk informasi lebih lanjut, lihat Memelihara Keamanan WMI.
- Penyedia harus mendaftar dengan WMI sebagai penyedia impersonasi. Untuk informasi selengkapnya, lihat Mendaftarkan Penyedia untuk Peniruan Identitas.
- Penyedia harus beralih ke tingkat keamanan aplikasi klien sebelum mengakses informasi istimewa. Untuk informasi selengkapnya, lihat Pengaturan Tingkat Peniruan Dalam Penyedia.
- Penyedia harus menangani kondisi kesalahan dengan benar jika akses ke informasi ini ditolak. Untuk informasi selengkapnya, lihat Menangani Pesan Yang Ditolak Akses di penyedia.
Mendaftarkan Penyedia untuk Peniruan Identitas
WMI hanya meneruskan SID aplikasi klien kepada penyedia yang telah terdaftar sebagai penyedia peniruan identitas. Mengaktifkan penyedia untuk melakukan peniruan mengharuskan Anda mengubah proses pendaftaran penyedia.
Prosedur berikut menjelaskan cara mendaftarkan penyedia untuk peniruan identitas. Prosedur ini mengasumsikan bahwa Anda sudah memahami proses pendaftaran. Untuk informasi selengkapnya tentang proses pendaftaran, lihat Mendaftarkan Penyedia.
Untuk mendaftarkan penyedia untuk pemalsuan identitas
Atur properti ImpersonationLevel dari kelas __Win32Provider yang mewakili penyedia Anda, ke nilai 1.
Properti ImpersonationLevel mendokumentasikan apakah penyedia mendukung peniruan identitas atau tidak. Pengaturan ImpersonationLevel ke 0 menunjukkan bahwa penyedia tidak meniru klien dan melakukan semua operasi yang diminta dalam konteks pengguna yang sama dengan WMI. Pengaturan ImpersonationLevel ke 1 menunjukkan bahwa penyedia menggunakan panggilan peniruan identitas untuk memeriksa operasi yang dilakukan atas nama klien.
Atur properti PerUserInitialization dari kelas __Win32Provider yang sama menjadi TRUE.
Nota
Jika Anda mendaftarkan penyedia dengan properti __Win32ProviderInitializeAsAdminFirst diatur ke TRUE, penyedia akan menggunakan token keamanan tingkat utas administrasi hanya selama fase inisialisasi. Meskipun panggilan ke CoImpersonateClient tidak gagal, penyedia menggunakan konteks keamanan WMI, bukan klien.
Contoh kode berikut menunjukkan cara mendaftarkan penyedia untuk peniruan identitas.
instance of __Win32Provider
{
CLSID = "{FD4F53E0-65DC-11d1-AB64-00C04FD9159E}";
ImpersonationLevel = 1;
Name = "MS_NT_EVENTLOG_PROVIDER";
PerUserInitialization = TRUE;
};
Mengatur Tingkat Pemalsuan Dalam Penyedia Layanan
Jika Anda mendaftarkan penyedia dengan properti kelas __Win32ProviderImpersonationLevel diatur ke 1, maka WMI memanggil penyedia Anda untuk meniru berbagai klien. Untuk menangani panggilan ini, gunakan fungsi CoImpersonateClient dan CoRevertToSelf COM dalam implementasi antarmukaIWbemServicesAnda.
FungsiCoImpersonateClient memungkinkan server untuk meniru klien yang melakukan panggilan. Dengan melakukan panggilan ke CoImpersonateClient ke dalam implementasi Anda dari IWbemServices, Anda mengizinkan penyedia Anda untuk mengatur token utas penyedia agar sesuai dengan token utas klien, dan dengan demikian mengimitasi klien. Jika Anda tidak memanggil CoImpersonateClient, penyedia Anda menjalankan kode pada tingkat keamanan administrator, sehingga menciptakan potensi kerentanan keamanan. Jika penyedia Anda untuk sementara waktu perlu bertindak sebagai administrator atau melakukan pemeriksaan akses secara manual, panggil CoRevertToSelf.
Berbeda dengan CoImpersonateClient, CoRevertToSelf adalah fungsi COM yang menangani tingkat peniruan utas. Dalam hal ini, CoRevertToSelf mengubah tingkat peniruan kembali ke pengaturan peniruan asli. Secara umum, penyedia awalnya bertindak sebagai administrator dan beralih antara CoImpersonateClient dan CoRevertToSelf tergantung pada apakah itu melakukan panggilan atas nama pemanggil atau atas nama dirinya sendiri. Adalah tanggung jawab penyedia untuk melakukan panggilan ini dengan benar agar tidak mengekspos lubang keamanan kepada pengguna akhir. Misalnya, penyedia hanya boleh memanggil fungsi Windows asli dalam urutan kode yang ditiru.
Nota
Tujuan CoImpersonateClient dan CoRevertToSelf adalah untuk menetapkan keamanan bagi penyedia. Jika Anda menentukan bahwa peniruan Anda telah gagal, Anda harus mengembalikan kode penyelesaian yang sesuai ke WMI melalui IWbemObjectSink::SetStatus. Untuk informasi selengkapnya, lihat Menangani Pesan Yang Ditolak Akses di penyedia.
Mempertahankan Tingkat Keamanan di Penyedia
Penyedia tidak dapat memanggil CoImpersonateClient sekali dalam implementasi IWbemServices dan menganggap bahwa kredensial peniruan tetap berlaku selama masa kerja penyedia. Sebagai gantinya, panggil CoImpersonateClient beberapa kali selama implementasi agar WMI tidak mengubah kredensial.
Kekhawatiran utama dalam menetapkan peniruan untuk penyedia adalah pengulangan kembali. Dalam konteks ini, reentrancy terjadi ketika penyedia mengirimkan permintaan informasi ke WMI dan menunggu hingga WMI memberikan respons kembali kepada penyedia. Intinya, utas eksekusi meninggalkan kode penyedia, hanya untuk memasukkan kembali kode di kemudian hari. Reentry adalah bagian dari desain COM, dan umumnya tidak menjadi perhatian. Namun, ketika thread memasuki WMI, thread mengambil level peniruan identitas WMI. Ketika utas kembali ke penyedia, Anda harus mengatur ulang tingkat peniruan dengan panggilan lain ke CoImpersonateClient.
Untuk melindungi diri Anda dari kerentanan keamanan di penyedia Anda, Anda harus melakukan panggilan masuk kembali ke WMI hanya dengan menyamar sebagai klien. Artinya, panggilan ke WMI harus dilakukan setelah Anda memanggil CoImpersonateClient dan sebelum memanggil CoRevertToSelf. Karena CoRevertToSelf menyebabkan peniruan identitas diatur ke tingkat pengguna tempat WMI dijalankan, umumnya LocalSystem, panggilan kembali ke WMI yang bersifat reentrant setelah memanggil CoRevertToSelf dapat memberi pengguna, serta penyedia mana pun yang dipanggil, lebih banyak kemampuan daripada yang seharusnya mereka miliki.
Nota
Jika Anda memanggil fungsi sistem atau metode antarmuka lain, konteks panggilan tidak dijamin akan dipertahankan.
Menangani Pesan Akses Ditolak di Penyedia
Sebagian besar pesan kesalahan Akses Ditolak muncul ketika klien meminta kelas atau informasi yang tidak mereka akses. Jika penyedia mengembalikan pesan kesalahan Akses Ditolak ke WMI dan WMI meneruskan ini ke klien, klien dapat menyimpulkan bahwa informasi ada. Dalam beberapa situasi, ini bisa menjadi pelanggaran keamanan. Oleh karena itu, penyedia Anda tidak boleh menyebarluaskan pesan ke klien. Sebaliknya, kumpulan kelas yang penyedia akan sediakan tidak boleh diekspos. Demikian pula, penyedia instans dinamis harus memanggil ke sumber data yang mendasar untuk menentukan cara menangani pesan Akses Ditolak. Adalah tanggung jawab penyedia untuk mereplikasi filosofi itu ke lingkungan WMI. Untuk informasi selengkapnya, lihat Pelaporan Instans Parsial dan Pelaporan Enumerasi Parsial.
Saat Anda menentukan bagaimana penyedia Anda harus menangani pesan Akses Ditolak, Anda harus menulis dan men-debug kode Anda. Saat debugging, seringkali mudah membedakan antara ditolak karena impersonasi rendah dan ditolak karena kesalahan dalam kode Anda. Anda dapat menggunakan pengujian sederhana dalam kode Anda untuk menentukan perbedaannya. Untuk informasi selengkapnya, lihat Men-debug Kode Akses Yang Ditolak.
Melaporkan Kejadian Parsial
Salah satu kejadian umum pesan Akses Ditolak adalah ketika WMI tidak dapat memberikan semua informasi untuk melengkapi instans. Misalnya, klien mungkin memiliki otoritas untuk melihat objek hard disk drive, tetapi mungkin tidak memiliki otoritas untuk melihat berapa banyak ruang yang tersedia pada hard disk drive itu sendiri. Penyedia Anda harus menentukan cara menangani situasi apa pun ketika penyedia tidak dapat sepenuhnya mengisi instans dengan properti karena pelanggaran akses.
WMI tidak memerlukan satu respons terhadap klien yang memiliki akses parsial ke instans. Sebagai gantinya, WMI versi 1.x memungkinkan penyedia salah satu opsi berikut:
Gagalkan seluruh operasi dengan WBEM_E_ACCESS_DENIED dan jangan kembalikan instansi apa pun.
Kembalikan objek kesalahan bersama dengan WBEM_E_ACCESS_DENIED, untuk menjelaskan alasan penolakan.
Kembalikan semua properti yang tersedia, dan isi properti yang tidak tersedia dengan NULL.
Nota
Pastikan bahwa mengembalikan WBEM_E_ACCESS_DENIED tidak membuat lubang keamanan di perusahaan Anda.
Melaporkan Enumerasi Parsial
Kejadian umum lain dari pelanggaran akses adalah ketika WMI tidak dapat mengembalikan semua enumerasi. Misalnya, klien mungkin memiliki akses untuk melihat semua objek komputer jaringan lokal, tetapi mungkin tidak memiliki akses untuk melihat objek komputer di luar domainnya. Penyedia Anda harus menentukan cara menangani situasi apa pun ketika enumerasi tidak dapat diselesaikan karena pelanggaran akses.
Seperti halnya penyedia instans, WMI tidak memerlukan satu respons terhadap enumerasi parsial. Sebagai gantinya, WMI versi 1.x memungkinkan penyedia salah satu opsi berikut:
Mengembalikan WBEM_S_NO_ERROR untuk semua instans yang dapat diakses oleh penyedia.
Jika Anda menggunakan opsi ini, pengguna tidak menyadari bahwa beberapa instance tidak tersedia. Sejumlah penyedia, seperti yang menggunakan Bahasa Kueri Terstruktur (SQL) dengan keamanan tingkat baris, mengembalikan hasil parsial yang berhasil menggunakan tingkat keamanan pemanggil untuk menentukan kumpulan hasil.
Gagalkan seluruh operasi dengan WBEM_E_ACCESS_DENIED dan tidak menghasilkan instans apa pun.
Penyedia dapat secara opsional menyertakan objek kesalahan yang menjelaskan situasi kepada klien. Perhatikan bahwa beberapa penyedia dapat mengakses sumber data secara serial dan mungkin tidak mengalami penolakan hingga sebagian melalui proses pemetaan.
Mengembalikan semua instans yang dapat diakses tetapi juga mengembalikan kode status nonerror WBEM_S_ACCESS_DENIED.
Penyedia harus mencatat penolakan selama enumerasi dan dapat terus menyediakan contoh, dengan menyelesaikan menggunakan kode status tanpa kesalahan. Penyedia juga dapat memilih untuk mengakhiri enumerasi pada penolakan pertama. Pembenaran untuk opsi ini adalah bahwa penyedia yang berbeda memiliki paradigma pengambilan yang berbeda. Penyedia mungkin telah mengirim instance sebelum menemukan pelanggaran akses. Beberapa penyedia dapat memilih untuk terus menyediakan instans lain dan yang lain mungkin ingin mengakhiri.
Karena struktur COM, Anda tidak dapat mengalihkan kembali informasi apa pun selama terjadi kesalahan, kecuali objek kesalahan. Oleh karena itu, Anda tidak dapat mengembalikan informasi dan kode kesalahan. Jika Anda memilih untuk mengembalikan informasi, Anda harus menggunakan kode status nonerror sebagai gantinya.
Memperbaiki Kode 'Akses Ditolak' Anda
Beberapa aplikasi mungkin menggunakan tingkat impersonasi yang lebih rendah dari RPC_C_IMP_LEVEL_IMPERSONATE. Dalam hal ini, sebagian besar panggilan peniruan yang dilakukan oleh penyedia untuk aplikasi klien akan gagal. Agar berhasil merancang dan mengimplementasikan penyedia layanan, Anda harus mengingat ide ini.
Secara default, satu-satunya tingkat peniruan lain yang dapat mengakses penyedia adalah RPC_C_IMP_LEVEL_IDENTIFY. Dalam kasus di mana aplikasi klien menggunakan RPC_C_IMP_LEVEL_IDENTIFY, CoImpersonateClient tidak mengembalikan kode kesalahan. Sebagai gantinya, penyedia meniru klien hanya untuk tujuan identifikasi. Oleh karena itu, sebagian besar metode Windows yang dipanggil oleh penyedia akan mengembalikan pesan akses yang ditolak. Ini tidak berbahaya dalam praktiknya, karena pengguna tidak akan diizinkan untuk melakukan sesuatu yang tidak pantas. Namun, mungkin berguna selama pengembangan penyedia untuk mengetahui apakah klien benar-benar ditiru atau tidak.
Kode memerlukan referensi berikut dan pernyataan #include untuk dikompilasi dengan benar.
#define _WIN32_DCOM
#include <iostream>
using namespace std;
#include <wbemidl.h>
Contoh kode berikut menunjukkan cara menentukan apakah penyedia telah berhasil meniru aplikasi klien.
DWORD dwImp = 0;
HANDLE hThreadTok;
DWORD dwBytesReturned;
BOOL bRes;
// You must call this before trying to open a thread token!
CoImpersonateClient();
bRes = OpenThreadToken(
GetCurrentThread(),
TOKEN_QUERY,
TRUE,
&hThreadTok
);
if (bRes == FALSE)
{
printf("Unable to read thread token (%d)\n", GetLastError());
return 0;
}
bRes = GetTokenInformation(
hThreadTok,
TokenImpersonationLevel,
&dwImp,
sizeof(DWORD),
&dwBytesReturned
);
if (!bRes)
{
printf("Unable to read impersonation level\n");
CloseHandle(hThreadTok);
return 0;
}
switch (dwImp)
{
case SecurityAnonymous:
printf("SecurityAnonymous\n");
break;
case SecurityIdentification:
printf("SecurityIdentification\n");
break;
case SecurityImpersonation:
printf("SecurityImpersonation\n");
break;
case SecurityDelegation:
printf("SecurityDelegation\n");
break;
default:
printf("Error. Unable to determine impersonation level\n");
break;
}
CloseHandle(hThreadTok);
Topik terkait