Bagikan melalui


Pertimbangan Keamanan untuk Data

Saat berhadapan dengan data di Windows Communication Foundation (WCF), Anda harus mempertimbangkan sejumlah kategori ancaman. Daftar berikut menunjukkan kelas ancaman terpenting yang terkait dengan pemrosesan data. WCF menyediakan alat untuk mengurangi ancaman ini.

  • Penolakan layanan

    Saat menerima data yang tidak tepercaya, data dapat menyebabkan sisi penerima mengakses sejumlah besar sumber daya yang tidak proporsional, seperti memori, utas, koneksi yang tersedia, atau siklus prosesor dengan menyebabkan komputasi yang panjang. Serangan penolakan layanan terhadap server dapat menyebabkannya crash dan tidak dapat memproses pesan dari klien lain yang sah.

  • Eksekusi kode berbahaya

    Data yang tidak tepercaya yang masuk menyebabkan sisi penerima menjalankan kode yang tidak diinginkannya.

  • Pengungkapan informasi

    Penyerang jarak jauh memaksa pihak penerima untuk menanggapi permintaannya sedemikian rupa untuk mengungkapkan lebih banyak informasi daripada yang diinginkannya.

Kode yang Diberikan Pengguna dan Keamanan Akses Kode

Sejumlah tempat di kode eksekusi infrastruktur Windows Communication Foundation (WCF) yang disediakan oleh pengguna. Misalnya, mesin serialisasi DataContractSerializer dapat memanggil pengakses set dan pengakses get properti yang disediakan pengguna. Infrastruktur saluran WCF juga dapat memanggil kelas turunan dari kelas Message yang disediakan pengguna.

Penulis kode bertanggung jawab untuk memastikan bahwa tidak ada kerentanan keamanan. Misalnya, jika Anda membuat tipe kontrak data dengan properti anggota data berjenis bilangan bulat, dan dalam implementasi pengakses set mengalokasikan array berdasarkan nilai properti, Anda mengekspos kemungkinan serangan penolakan layanan jika pesan berbahaya berisi nilai yang sangat besar untuk anggota data ini. Secara umum, hindari alokasi apa pun berdasarkan data masuk atau pemrosesan panjang dalam kode yang disediakan pengguna (terutama jika pemrosesan yang panjang dapat disebabkan oleh sejumlah kecil data masuk). Saat melakukan analisis keamanan kode yang disediakan pengguna, pastikan juga untuk mempertimbangkan semua kasus kegagalan (yaitu, semua cabang kode tempat pengecualian dilemparkan).

Contoh utama kode yang disediakan pengguna adalah kode di dalam implementasi layanan Anda untuk setiap operasi. Keamanan implementasi layanan Anda adalah tanggung jawab Anda. Sangat mudah untuk secara tidak sengaja membuat implementasi operasi yang tidak aman yang dapat mengakibatkan kerentanan penolakan layanan. Misalnya, operasi yang mengambil string dan mengembalikan daftar pelanggan dari database yang namanya dimulai dengan string tersebut. Jika Anda bekerja dengan database besar dan string yang diteruskan hanyalah satu huruf, kode Anda dapat mencoba membuat pesan yang lebih besar dari semua memori yang tersedia, menyebabkan seluruh layanan gagal. (Sebuah OutOfMemoryException tidak dapat dipulihkan dalam .NET Framework dan selalu mengakibatkan penghentian aplikasi Anda.)

Anda harus memastikan bahwa tidak ada kode berbahaya yang dicolokkan ke berbagai titik ekstensibilitas. Ini sangat relevan ketika berjalan di bawah kepercayaan parsial, berurusan dengan jenis dari rakitan yang tepercaya sebagian, atau membuat komponen yang dapat digunakan oleh kode yang dipercaya sebagian. Untuk informasi selengkapnya, lihat "Ancaman Kepercayaan Parsial" di bagian selanjutnya.

Perhatikan bahwa saat berjalan dalam kepercayaan parsial, infrastruktur serialisasi kontrak data hanya mendukung subset terbatas dari model pemrograman kontrak data - misalnya, anggota data privat atau jenis yang menggunakan atribut SerializableAttribute tidak didukung. Untuk informasi selengkapnya, lihat Kepercayaan Sebagian.

Catatan

Keamanan Akses Kode (CAS) tidak digunakan lagi di semua versi .NET Framework dan .NET. Versi terbaru .NET tidak mematuhi anotasi CAS dan menghasilkan kesalahan jika API terkait CAS digunakan. Pengembang harus mencari cara alternatif untuk menyelesaikan tugas keamanan.

Menghindari Pengungkapan Informasi yang Tidak Disengaja

Saat merancang jenis yang dapat diserialisasikan dengan mempertimbangkan keamanan, pengungkapan informasi adalah masalah yang mungkin terjadi.

Pertimbangkan poin-poin berikut:

  • Model pemrograman DataContractSerializer memungkinkan paparan data privat dan internal di luar jenis atau perakitan selama serialisasi. Selain itu, bentuk jenis dapat diekspos selama ekspor skema. Pastikan untuk memahami proyeksi serialisasi jenis Anda. Jika Anda tidak ingin sesuatu terekspos, nonaktifkan serialisasi (misalnya, dengan tidak menerapkan atribut DataMemberAttribute dalam kasus kontrak data).

  • Ketahuilah bahwa jenis yang sama mungkin memiliki beberapa proyeksi serialisasi, tergantung serializer yang digunakan. Jenis yang sama dapat mengekspos satu kumpulan data saat digunakan dengan DataContractSerializer dan kumpulan data lainnya saat digunakan dengan XmlSerializer. Sengaja menggunakan serializer yang salah dapat menyebabkan pengungkapan informasi.

  • Menggunakan XmlSerializer dalam mode panggilan prosedur jarak jauh (RPC)/dikodekan lama dapat secara tidak sengaja mengekspos bentuk grafik objek di sisi pengirim ke sisi penerima.

Mencegah Serangan Penolakan Layanan

Kuota

Menyebabkan sisi penerima mengalokasikan sejumlah besar memori adalah potensi serangan penolakan layanan. Meskipun bagian ini berkonsentrasi pada masalah konsumsi memori yang timbul dari pesan besar, serangan lain dapat terjadi. Misalnya, pesan dapat menggunakan jumlah waktu pemrosesan yang tidak proporsional.

Serangan penolakan layanan biasanya dimitigasi menggunakan kuota. Ketika kuota terlampaui, pengecualian QuotaExceededException biasanya ditampilkan. Tanpa kuota, pesan berbahaya dapat menyebabkan semua memori yang tersedia dapat diakses, mengakibatkan pengecualian OutOfMemoryException, atau semua tumpukan yang tersedia untuk diakses, menghasilkan StackOverflowException.

Skenario kuota terlampaui dapat dipulihkan; jika ditemukan dalam layanan yang sedang berjalan, pesan yang saat ini sedang diproses dibuang dan layanan terus berjalan dan memproses pesan lebih lanjut. Skenario kehabisan memori dan luapan tumpukan, namun, tidak dapat dipulihkan di mana saja dalam .NET Framework; layanan berakhir jika mengalami pengecualian tersebut.

Kuota dalam WCF tidak melibatkan praalokasi apa pun. Misalnya, jika kuota MaxReceivedMessageSize (ditemukan di berbagai kelas) diatur ke 128 KB, itu tidak berarti bahwa 128 KB secara otomatis dialokasikan untuk setiap pesan. Jumlah aktual yang dialokasikan tergantung ukuran pesan masuk yang sebenarnya.

Banyak kuota yang tersedia di lapisan transportasi. Ini adalah kuota yang diberlakukan oleh saluran transportasi tertentu yang digunakan (HTTP, TCP, dan sebagainya). Meskipun topik ini membahas beberapa kuota ini, kuota ini dijelaskan secara mendetail dalam Kuota Transportasi.

Kerentanan Hashtable

Kerentanan ada ketika kontrak data berisi hashtable atau koleksi. Masalah terjadi jika sejumlah besar nilai dimasukkan ke dalam hashtable di mana sejumlah besar nilai tersebut menghasilkan nilai hash yang sama. Ini dapat digunakan sebagai serangan DOS. Kerentanan ini dapat dimitigasi dengan mengatur kuota pengikatan MaxReceivedMessageSize. Perawatan harus dilakukan saat menetapkan kuota ini untuk mencegah serangan tersebut. Kuota ini menempatkan batas atas pada ukuran pesan WCF. Selain itu, hindari menggunakan hashtable atau koleksi dalam kontrak data Anda.

Membatasi Konsumsi Memori Tanpa Streaming

Model keamanan di sekitar pesan besar tergantung pada apakah streaming sedang digunakan. Dalam kasus dasar yang tidak dialirkan, pesan di-buffer ke dalam memori. Dalam hal ini, gunakan kuota MaxReceivedMessageSize pada TransportBindingElement atau pada pengikatan yang disediakan sistem untuk melindungi dari pesan besar dengan membatasi ukuran pesan maksimum untuk diakses. Perhatikan bahwa layanan mungkin memproses beberapa pesan secara bersamaan, dalam hal ini semuanya berada dalam memori. Gunakan fitur pembatasan untuk mengurangi ancaman ini.

Perhatikan juga bahwa MaxReceivedMessageSize tidak menempatkan batas atas pada konsumsi memori per pesan, tetapi membatasinya dalam faktor konstan. Misalnya, jika MaxReceivedMessageSize adalah 1 MB dan pesan 1 MB diterima dan kemudian dideserialisasi, memori tambahan diperlukan untuk berisi grafik objek yang dideserialisasi, menghasilkan total konsumsi memori dengan baik lebih dari 1 MB. Untuk alasan ini, hindari membuat jenis yang dapat diserialisasikan yang dapat mengakibatkan konsumsi memori yang signifikan tanpa banyak data masuk. Misalnya, kontrak data "MyContract" dengan 50 bidang anggota data opsional dan 100 bidang privat tambahan dapat dibuat dengan konstruksi XML "<MyContract/>". XML ini menghasilkan memori yang diakses untuk 150 bidang. Perhatikan bahwa anggota data bersifat opsional secara default. Masalahnya diperjelas ketika jenis tersebut adalah bagian dari array.

MaxReceivedMessageSize saja tidak cukup untuk mencegah semua penolakan serangan layanan. Misalnya, deserializer dapat dipaksa untuk mendeserialisasi grafik objek berlapis dalam (objek yang berisi objek lain yang berisi objek lain, dan sebagainya) oleh pesan masuk. Baik metode pemanggilan DataContractSerializer dan XmlSerializer dengan cara berlapis untuk membatalkan serialisasi grafik tersebut. Pengumpulan panggilan metode yang dalam dapat mengakibatkan StackOverflowException yang tidak dapat dipulihkan. Ancaman ini dikurangi dengan menyetel kuota MaxDepth untuk membatasi tingkat pelapisan XML, seperti yang dibahas di bagian "Menggunakan XML dengan Aman" nanti di topik.

Mengatur kuota tambahan ke MaxReceivedMessageSize sangat penting saat menggunakan pengodean XML biner. Menggunakan pengodean biner agak setara dengan kompresi: sekelompok kecil byte dalam pesan masuk mungkin mewakili banyak data. Jadi, bahkan pesan yang masuk ke dalam batas MaxReceivedMessageSize dapat memakan lebih banyak memori dalam bentuk yang diperluas sepenuhnya. Untuk mengurangi ancaman khusus XML tersebut, semua kuota pembaca XML harus diatur dengan benar, seperti yang dibahas di bagian "Menggunakan XML Dengan Aman" nanti dalam topik ini.

Membatasi Konsumsi Memori dengan Streaming

Saat streaming, Anda dapat menggunakan pengaturan MaxReceivedMessageSize kecil untuk melindungi dari serangan penolakan layanan. Namun, skenario yang lebih rumit dimungkinkan dengan streaming. Misalnya, layanan unggahan file menerima file yang lebih besar dari semua memori yang tersedia. Dalam hal ini, atur MaxReceivedMessageSize ke nilai yang sangat besar, mengharapkan bahwa hampir tidak ada data yang di-buffer dalam memori dan pesan mengalir langsung ke disk. Jika pesan berbahaya entah bagaimana dapat memaksa WCF untuk menyangga data alih-alih mengalirkannya dalam hal ini, MaxReceivedMessageSize tidak lagi melindungi dari pesan yang mengakses semua memori yang tersedia.

Untuk mengurangi ancaman ini, pengaturan kuota tertentu ada di berbagai komponen pemrosesan data WCF yang membatasi buffering. Yang paling penting adalah properti MaxBufferSize pada berbagai elemen pengikatan transportasi dan pengikatan standar. Saat streaming, kuota ini harus diatur dengan mempertimbangkan jumlah maksimum memori yang ingin Anda alokasikan per pesan. Seperti halnya MaxReceivedMessageSize, setelan tidak menempatkan maksimum absolut pada konsumsi memori tetapi hanya membatasinya dalam faktor konstan. Selain itu, seperti halnya MaxReceivedMessageSize, waspadai kemungkinan beberapa pesan diproses secara bersamaan.

Detail MaxBufferSize

Properti MaxBufferSize membatasi buffering massal yang dilakukan WCF. Misalnya, WCF selalu mem-buffer header SOAP dan kesalahan SOAP, serta setiap bagian MIME yang ditemukan tidak dalam urutan pembacaan alami dalam pesan Message Transmission Optimization Mechanism (MTOM). Pengaturan ini membatasi jumlah buffering dalam semua kasus ini.

WCF menyelesaikan ini dengan meneruskan nilai MaxBufferSize ke berbagai komponen yang mungkin buffer. Misalnya, beberapa overload CreateMessage kelas Message mengambil parameter maxSizeOfHeaders. WCF meneruskan nilai MaxBufferSize ke parameter ini untuk membatasi jumlah buffering header SOAP. Penting untuk mengatur parameter ini saat menggunakan kelas Message secara langsung. Secara umum, saat menggunakan komponen di WCF yang mengambil parameter kuota, penting untuk memahami implikasi keamanan parameter ini dan mengaturnya dengan benar.

Encoder pesan MTOM juga memiliki setelan MaxBufferSize. Saat menggunakan pengikatan standar, ini disetel secara otomatis ke nilai tingkat transportasi MaxBufferSize. Namun, saat menggunakan elemen pengikatan encoder pesan MTOM untuk membuat pengikatan khusus, penting untuk menyetel properti MaxBufferSize ke nilai aman saat streaming digunakan.

Serangan Streaming berbasis XML

MaxBufferSize saja tidak cukup untuk memastikan bahwa WCF tidak dapat dipaksa ke buffering saat streaming diharapkan. Misalnya, pembaca XML WCF selalu mem-buffer seluruh tag mulai elemen XML saat mulai membaca elemen baru. Ini dilakukan agar namespace layanan dan atribut diproses dengan benar. Jika MaxReceivedMessageSize dikonfigurasi menjadi besar (misalnya, untuk mengaktifkan skenario streaming file besar langsung ke disk), pesan berbahaya dapat dibangun di mana seluruh isi pesan adalah tag mulai elemen XML besar. Upaya untuk membacanya menghasilkan OutOfMemoryException. Ini adalah salah satu dari banyak kemungkinan serangan penolakan layanan berbasis XML yang semuanya dapat dimitigasi menggunakan kuota pembaca XML, yang dibahas di bagian "Menggunakan XML Dengan Aman" nanti dalam topik ini. Saat streaming, sangat penting untuk mengatur semua kuota ini.

Mencampur Model Pemrograman Streaming dan Buffering

Banyak kemungkinan serangan muncul dari pencampuran model pemrograman streaming dan non-streaming dalam layanan yang sama. Misalkan ada kontrak layanan dengan dua operasi: satu melakukan Stream dan yang lain mengambil array dari beberapa jenis kustom. Anggap juga bahwa MaxReceivedMessageSize disetel ke nilai besar untuk memungkinkan operasi pertama memproses aliran besar. Sayangnya, ini berarti bahwa pesan besar sekarang dapat dikirim ke operasi kedua juga, dan deserializer buffer data dalam memori sebagai array sebelum operasi dipanggil. Ini adalah potensi serangan penolakan layanan: MaxBufferSize kuota tidak membatasi ukuran isi pesan, yang merupakan fungsi deserializer.

Untuk alasan ini, hindari mencampur operasi berbasis aliran dan non-streaming dalam kontrak yang sama. Jika Anda benar-benar harus mencampur dua model pemrograman, gunakan tindakan pencegahan berikut:

  • Matikan fitur IExtensibleDataObject dengan menyetel properti IgnoreExtensionDataObject dari ServiceBehaviorAttribute ke true. Ini memastikan bahwa hanya anggota yang merupakan bagian dari kontrak yang dideserialisasi.

  • Setel properti MaxItemsInObjectGraph dari DataContractSerializer ke nilai aman. Kuota ini juga tersedia pada atribut ServiceBehaviorAttribute atau melalui konfigurasi. Kuota ini membatasi jumlah objek yang dideserialisasi dalam satu episode deserialisasi. Biasanya, setiap parameter operasi atau bagian isi pesan dalam kontrak pesan dideserialisasi dalam satu episode. Saat deserialisasi array, setiap entri array dihitung sebagai objek terpisah.

  • Atur semua kuota pembaca XML ke nilai aman. Perhatikan MaxDepth, MaxStringContentLength, dan MaxArrayLength dan hindari string dalam operasi non-streaming.

  • Tinjau daftar jenis yang diketahui, dengan mengingat bahwa salah satu dari mereka dapat dipakai kapan saja (lihat bagian "Mencegah Jenis yang Tidak Diinginkan dari Dimuat" nanti dalam topik ini).

  • Jangan gunakan jenis apa pun yang mengimplementasikan antarmuka IXmlSerializable yang mem-buffer banyak data. Jangan tambahkan jenis tersebut ke daftar jenis yang diketahui.

  • Jangan gunakan XmlElement, XmlNode array, Byte array, atau jenis yang mengimplementasikan ISerializable dalam kontrak.

  • Jangan gunakan XmlElement, XmlNode array, Byte array, atau tipe yang mengimplementasikan ISerializable dalam daftar tipe yang diketahui.

Tindakan pencegahan sebelumnya berlaku ketika operasi yang tidak dialirkan menggunakan DataContractSerializer. Jangan pernah mencampur model pemrograman streaming dan non-streaming pada layanan yang sama jika Anda menggunakan XmlSerializer, karena tidak memiliki perlindungan kuota MaxItemsInObjectGraph.

Serangan Aliran Lambat

Kelas serangan penolakan layanan streaming tidak melibatkan konsumsi memori. Sebaliknya, serangan itu melibatkan pengirim atau penerima data yang lambat. Saat menunggu data dikirim atau diterima, sumber daya seperti utas dan koneksi yang tersedia habis. Situasi ini dapat muncul baik sebagai akibat dari serangan berbahaya atau dari pengirim/penerima yang sah pada koneksi jaringan yang lambat.

Untuk mengurangi serangan ini, atur batas waktu transportasi dengan benar. Untuk informasi lebih lanjut, lihat Kuota Transportasi. Kedua, jangan pernah menggunakan operasi Read atau Write yang sinkron saat bekerja dengan aliran di WCF.

Menggunakan XML Dengan Aman

Catatan

Meskipun bagian ini tentang XML, informasi juga berlaku untuk dokumen JavaScript Object Notation (JSON). Kuota bekerja dengan cara yang sama, menggunakan Pemetaan Antara JSON dan XML.

Pembaca XML Aman

Xml Infoset membentuk dasar semua pemrosesan pesan di WCF. Saat menerima data XML dari sumber yang tidak tepercaya, ada sejumlah kemungkinan serangan penolakan layanan yang harus dimitigasi. WCF menyediakan pembaca XML khusus yang aman. Pembaca ini dibuat secara otomatis saat menggunakan salah satu pengodean standar dalam WCF (teks, biner, atau MTOM).

Beberapa fitur keamanan pada pembaca ini selalu aktif. Misalnya, pembaca tidak pernah memproses definisi jenis dokumen (DTD), yang merupakan sumber potensial serangan penolakan layanan dan tidak boleh muncul dalam pesan SOAP yang sah. Fitur keamanan lainnya termasuk kuota pembaca yang harus dikonfigurasi, yang dijelaskan di bagian berikut.

Saat bekerja secara langsung dengan pembaca XML (seperti saat menulis pembuat enkode kustom Anda sendiri atau saat bekerja secara langsung dengan kelas Message), selalu gunakan pembaca aman WCF saat ada kemungkinan bekerja dengan data yang tidak tepercaya. Buat pembaca aman dengan memanggil salah satu overload metode pabrik statis CreateTextReader, CreateBinaryReader, atau CreateMtomReader di kelas XmlDictionaryReader. Saat membuat pembaca, berikan nilai kuota aman. Jangan panggil overload metode Create. Ini tidak membuat pembaca WCF. Sebaliknya, pembaca dibuat yang tidak dilindungi oleh fitur keamanan yang dijelaskan di bagian ini.

Kuota Pembaca

Pembaca XML aman memiliki lima kuota yang dapat dikonfigurasi. Ini biasanya dikonfigurasi menggunakan properti ReaderQuotas pada elemen pengikatan pengodean atau pengikatan standar, atau dengan menggunakan objek XmlDictionaryReaderQuotas yang diteruskan saat membuat pembaca.

MaxBytesPerRead

Kuota ini membatasi jumlah byte yang dibaca dalam satu operasi Read saat membaca tag awal elemen dan atributnya. (Dalam kasus yang tidak dialirkan, nama elemen itu sendiri tidak dihitung terhadap kuota.) MaxBytesPerRead penting karena alasan berikut:

  • Nama elemen dan atributnya selalu di-buffer dalam memori saat dibaca. Oleh karena itu, penting untuk mengatur kuota ini dengan benar dalam mode streaming untuk mencegah buffering yang berlebihan saat streaming diharapkan. Lihat bagian kuota MaxDepth untuk informasi tentang jumlah buffering aktual yang terjadi.

  • Terlalu banyak atribut XML dapat mengurangi waktu pemrosesan yang tidak proporsional karena keunikan nama atribut harus diperiksa. MaxBytesPerRead menanggulangi ancaman ini.

MaxDepth

Kuota ini membatasi kedalaman pelapisan maksimum elemen XML. Misalnya, dokumen "<A><B><C/></B></A>" memiliki kedalaman berlapis tiga. MaxDepth penting karena alasan berikut:

  • MaxDepth berinteraksi dengan MaxBytesPerRead: pembaca selalu menyimpan data dalam memori untuk elemen saat ini dan semua pendahulunya, sehingga konsumsi memori maksimum pembaca sebanding dengan produk dari kedua setelan ini.

  • Saat mendeserialisasi grafik objek berlapis dalam, alat deserialisasi dipaksa untuk mengakses seluruh tumpukan dan menghilangkan yang tidak dapat dipulihkan StackOverflowException. Korelasi langsung ada di antara pelapisan XML dan pelapisan objek untuk DataContractSerializer dan XmlSerializer. Gunakan MaxDepth untuk mengurangi ancaman ini.

MaxNameTableCharCount

Kuota ini membatasi ukuran nametable pembaca. Papan nama berisi string tertentu (seperti namespace layanan dan awalan) yang dijumpai saat memproses dokumen XML. Karena string ini di-buffer dalam memori, atur kuota ini untuk mencegah buffering yang berlebihan saat streaming diharapkan.

MaxStringContentLength

Kuota ini membatasi ukuran string maksimum yang ditampilkan pembaca XML. Kuota ini tidak membatasi konsumsi memori di pembaca XML itu sendiri, tetapi dalam komponen yang menggunakan pembaca. Misalnya, saat DataContractSerializer menggunakan pembaca yang diamankan dengan MaxStringContentLength, string yang lebih besar dari kuota ini tidak akan dideserialisasi. Saat menggunakan kelas XmlDictionaryReader secara langsung, tidak semua metode menghormati kuota ini, tetapi hanya metode yang dirancang khusus untuk membaca string, seperti metode ReadContentAsString. Properti Value pada pembaca tidak terpengaruh oleh kuota ini, dan karenanya tidak boleh digunakan saat perlindungan yang diberikan kuota ini diperlukan.

MaxArrayLength

Kuota ini membatasi ukuran maksimum rangkaian primitif yang ditampilkan pembaca XML, termasuk rangkaian byte. Kuota ini tidak membatasi penggunaan memori di pembaca XML itu sendiri, tetapi dalam komponen apa pun yang menggunakan pembaca. Misalnya, saat DataContractSerializer menggunakan pembaca yang diamankan dengan MaxArrayLength, rangkaian byte yang lebih besar dari kuota ini tidak akan dideserialisasi. Penting untuk mengatur kuota ini saat mencoba mencampur model pemrograman streaming dan buffer dalam satu kontrak. Ingatlah bahwa saat menggunakan kelas XmlDictionaryReader secara langsung, hanya metode yang dirancang khusus untuk membaca array dengan ukuran arbitrer dari tipe primitif tertentu, seperti ReadInt32Array, yang mematuhi kuota ini.

Ancaman Khusus untuk Pengodean Biner

Pengodean XML biner yang didukung WCF mencakup fitur string kamus. String besar dapat dikodekan hanya menggunakan beberapa byte. Ini memungkinkan perolehan performa yang signifikan, tetapi memperkenalkan ancaman penolakan layanan baru yang harus dimitigasi.

Ada dua jenis kamus: statis dan dinamis. Kamus statis adalah daftar bawaan string panjang yang mungkin diwakili menggunakan kode pendek dalam pengodean biner. Daftar string ini diperbaiki ketika pembaca dibuat dan tidak dapat dimodifikasi. Tidak ada string dalam kamus statis yang digunakan WCF secara default cukup besar untuk menimbulkan ancaman penolakan layanan yang serius, meskipun mungkin masih digunakan dalam serangan ekspansi kamus. Dalam skenario lanjutan di mana Anda menyediakan kamus statis Anda sendiri, berhati-hatilah saat memperkenalkan string kamus besar.

Fitur kamus dinamis memungkinkan pesan untuk menentukan string mereka sendiri dan mengaitkannya dengan kode pendek. Pemetaan string-ke-kode ini disimpan dalam memori selama seluruh sesi komunikasi, sehingga pesan berikutnya tidak perlu mengirim ulang string dan dapat menggunakan kode yang sudah ditentukan. String ini mungkin memiliki panjang arbitrer dan dengan demikian menimbulkan ancaman yang lebih serius daripada yang ada dalam kamus statis.

Ancaman pertama yang harus dimitigasi adalah kemungkinan kamus dinamis (tabel pemetaan string-ke-kode) menjadi terlalu besar. Kamus ini dapat diperluas selama beberapa pesan, sehingga kuota MaxReceivedMessageSize tidak menawarkan perlindungan karena hanya berlaku untuk setiap pesan secara terpisah. Oleh karena itu, properti MaxSessionSize terpisah ada pada BinaryMessageEncodingBindingElement yang membatasi ukuran kamus.

Tidak seperti kebanyakan kuota lainnya, kuota ini juga berlaku saat menulis pesan. Jika terlampaui saat membaca pesan, QuotaExceededException pesan ditampilkan seperti biasa. Jika terlampaui saat menulis pesan, string apa pun yang menyebabkan kuota terlampaui akan ditulis apa adanya, tanpa menggunakan fitur kamus dinamis.

Ancaman Perluasan Kamus

Kelas serangan khusus biner yang signifikan muncul dari ekspansi kamus. Pesan kecil dalam bentuk biner dapat berubah menjadi pesan yang sangat besar dalam bentuk tekstual yang sepenuhnya diperluas jika menggunakan fitur kamus string yang luas. Faktor ekspansi untuk string kamus dinamis dibatasi oleh kuota MaxSessionSize, karena tidak ada string kamus dinamis yang melebihi ukuran maksimum seluruh kamus.

Properti MaxNameTableCharCount, MaxStringContentLength, dan MaxArrayLength hanya membatasi konsumsi memori. Mereka biasanya tidak diperlukan untuk mengurangi ancaman apa pun dalam penggunaan yang tidak dialirkan karena penggunaan memori sudah dibatasi oleh MaxReceivedMessageSize. Namun, MaxReceivedMessageSize menghitung byte praekspansi. Ketika pengodean biner sedang digunakan, konsumsi memori berpotensi melampaui MaxReceivedMessageSize, hanya dibatasi oleh faktor MaxSessionSize. Untuk alasan ini, penting untuk selalu mengatur semua kuota pembaca (terutama MaxStringContentLength) saat menggunakan pengodean biner.

Saat menggunakan pengodean biner bersama dengan DataContractSerializer, antarmuka IExtensibleDataObject dapat disalahgunakan untuk memasang serangan ekspansi kamus. Antarmuka ini pada dasarnya menyediakan penyimpanan tak terbatas untuk data arbitrer yang bukan bagian dari kontrak. Jika kuota tidak dapat diatur cukup rendah sehingga MaxSessionSize dikalikan dengan MaxReceivedMessageSize tidak menimbulkan masalah, nonaktifka fiturn IExtensibleDataObject saat menggunakan pengodean biner. Setel properti IgnoreExtensionDataObject ke true pada atribut ServiceBehaviorAttribute. Atau, jangan mengimplementasikan antarmuka IExtensibleDataObject. Untuk informasi selengkapnya, lihat Kontrak Data yang Kompatibel Dengan Penerusan.

Ringkasan Kuota

Tabel berikut ini meringkas panduan tentang kuota.

Kondisi Kuota penting yang akan ditetapkan
Tidak ada streaming atau streaming pesan kecil, teks, atau pengodean MTOM MaxReceivedMessageSize, MaxBytesPerRead, dan MaxDepth
Tidak ada streaming atau streaming pesan kecil, pengodean biner MaxReceivedMessageSize, MaxSessionSize, dan semua ReaderQuotas
Streaming pesan besar, teks, atau pengodean MTOM MaxBufferSize dan semua ReaderQuotas
Streaming pesan besar, pengodean biner MaxBufferSize, MaxSessionSize, dan semua ReaderQuotas
  • Batas waktu tingkat transportasi harus selalu diatur dan tidak pernah menggunakan baca/tulis sinkron saat streaming sedang digunakan, terlepas dari apakah Anda melakukan streaming pesan besar atau kecil.

  • Ketika ragu tentang kuota, atur ke nilai aman daripada membiarkannya terbuka.

Mencegah Eksekusi Kode Berbahaya

Kelas umum ancaman berikut dapat menjalankan kode dan memiliki efek yang tidak diinginkan:

  • Deserializer memuat jenis berbahaya, tidak aman, atau sensitif terhadap keamanan.

  • Pesan masuk menyebabkan deserializer membuat instans jenis yang biasanya aman sewaktu-waktu memiliki konsekuensi yang tidak diinginkan.

Bagian berikut membahas kelas ancaman ini lebih lanjut.

DataContractSerializer

(Untuk informasi keamanan di XmlSerializer, lihat dokumentasi yang relevan.) Model keamanan untuk XmlSerializer mirip dengan DataContractSerializer, dan sebagian besar berbeda dalam detailnya. Misalnya, atribut XmlIncludeAttribute digunakan untuk penyertaan jenis dan bukan atribut KnownTypeAttribute. Namun, beberapa ancaman yang unik untuk XmlSerializer dibahas nanti dalam topik ini.

Mencegah Tipe yang Tidak Diinginkan Dimuat

Memuat jenis yang tidak diinginkan mungkin memiliki konsekuensi yang signifikan, apakah jenisnya berbahaya atau hanya memiliki efek samping yang sensitif terhadap keamanan. Jenis mungkin berisi kerentanan keamanan yang dapat dieksploitasi, melakukan tindakan sensitif keamanan di konstruktor atau konstruktor kelasnya, memiliki jejak memori besar yang memfasilitasi serangan penolakan layanan, atau dapat melemparkan pengecualian yang tidak dapat dipulihkan. Jenis mungkin memiliki konstruktor kelas yang berjalan segera setelah jenis dimuat dan sebelum instans apa pun dibuat. Untuk alasan ini, penting untuk mengontrol kumpulan jenis yang mungkin dimuat oleh deserializer.

Deserialisasi DataContractSerializer dengan cara yang digabungkan secara longgar. Ini tidak pernah membaca jenis runtime bahasa umum (CLR) dan nama rakitan dari data masuk. Ini mirip dengan perilaku XmlSerializer, tetapi berbeda dari perilaku NetDataContractSerializer, BinaryFormatter, dan SoapFormatter. Konektor longgar memperkenalkan tingkat keamanan, karena penyerang jarak jauh tidak dapat menunjukkan jenis arbitrer untuk dimuat hanya dengan memberi nama jenis tersebut dalam pesan.

DataContractSerializer selalu diizinkan untuk memuat jenis yang saat ini diharapkan sesuai dengan kontrak. Misalnya, jika kontrak data memiliki anggota data tipe Customer, DataContractSerializer diizinkan untuk memuat tipe Customer saat deserialize anggota data ini.

Selain itu, DataContractSerializer mendukung polimorfisme. Anggota data dapat dinyatakan sebagai Object, tetapi data masuk mungkin berisi instans Customer. Ini hanya mungkin jika jenis Customer telah dibuat "diketahui" oleh deserializer melalui salah satu mekanisme berikut:

  • KnownTypeAttribute atribut diterapkan ke suatu jenis.

  • KnownTypeAttribute atribut yang menentukan metode yang mengembalikan daftar jenis.

  • Atribut ServiceKnownTypeAttribute.

  • Bagian konfigurasi KnownTypes.

  • Daftar jenis yang diketahui secara eksplisit diteruskan ke DataContractSerializer selama konstruksi, jika menggunakan serializer secara langsung.

Masing-masing mekanisme ini meningkatkan area permukaan dengan memperkenalkan lebih banyak jenis yang dapat dimuat oleh deserializer. Kontrol masing-masing mekanisme ini untuk memastikan tidak ada jenis berbahaya atau tidak diinginkan yang ditambahkan ke daftar jenis yang diketahui.

Setelah jenis yang diketahui berada dalam ruang lingkup, itu dapat dimuat kapan saja, dan contoh jenis dapat dibuat, bahkan jika kontrak melarang untuk benar-benar menggunakannya. Misalnya, jenis "MyDangerousType" ditambahkan ke daftar jenis yang diketahui menggunakan salah satu mekanisme di atas. Ini berarti bahwa:

  • MyDangerousType dimuat dan konstruktor kelasnya berjalan.

  • Bahkan saat mendeserialisasi kontrak data dengan anggota data string, pesan berbahaya masih dapat menyebabkan instans MyDangerousType untuk dibuat. Kode di MyDangerousType, seperti setter properti, dapat berjalan. Setelah ini selesai, deserializer mencoba menetapkan instance ini ke anggota data string dan gagal dengan pengecualian.

Saat menulis metode yang mengembalikan daftar jenis yang diketahui, atau saat meneruskan daftar secara langsung ke konstruktor DataContractSerializer, pastikan kode yang menyiapkan daftar aman dan hanya beroperasi pada data tepercaya.

Jika menentukan jenis konfigurasi yang diketahui, pastikan file konfigurasi aman. Selalu gunakan nama yang kuat dalam konfigurasi (dengan menentukan kunci publik rakitan yang ditandatangani tempat jenis berada), tetapi jangan tentukan versi jenis yang akan dimuat. Pemuat jenis secara otomatis memilih versi terbaru, jika memungkinkan. Jika Anda menentukan versi tertentu dalam konfigurasi, Anda menjalankan risiko berikut: Jenis mungkin memiliki kerentanan keamanan yang mungkin diperbaiki dalam versi mendatang, tetapi versi yang rentan masih dimuat karena secara eksplisit ditentukan dalam konfigurasi.

Memiliki terlalu banyak jenis yang diketahui memiliki konsekuensi lain: DataContractSerializer membuat cache kode serialisasi/deserialisasi di domain aplikasi, dengan entri untuk setiap jenis yang harus diserialisasikan dan deserialisasi. Cache ini tidak pernah dibersihkan selama domain aplikasi berjalan. Oleh karena itu, penyerang yang menyadari bahwa aplikasi menggunakan banyak jenis yang diketahui dapat menyebabkan deserialisasi semua jenis ini, menyebabkan cache mengonsumsi memori dalam jumlah yang tidak proporsional.

Mencegah Jenis Berada dalam Status yang Tidak Diinginkan

Jenis mungkin memiliki batasan konsistensi internal yang harus diberlakukan. Perawatan harus dilakukan untuk menghindari melanggar batasan ini selama deserialisasi.

Contoh jenis berikut mewakili status airlock pada pesawat ruang angkasa, dan memberlakukan batasan bahwa pintu dalam dan luar tidak dapat terbuka pada saat yang sama.

[DataContract]
public class SpaceStationAirlock
{
    [DataMember]
    private bool innerDoorOpenValue = false;
    [DataMember]
    private bool outerDoorOpenValue = false;

    public bool InnerDoorOpen
    {
        get { return innerDoorOpenValue; }
        set
        {
            if (value & outerDoorOpenValue)
                throw new Exception("Cannot open both doors!");
            else innerDoorOpenValue = value;
        }
    }
    public bool OuterDoorOpen
    {
        get { return outerDoorOpenValue; }
        set
        {
            if (value & innerDoorOpenValue)
                throw new Exception("Cannot open both doors!");
            else outerDoorOpenValue = value;
        }
    }
}
<DataContract()> _
Public Class SpaceStationAirlock
    <DataMember()> Private innerDoorOpenValue As Boolean = False
    <DataMember()> Private outerDoorOpenValue As Boolean = False

    Public Property InnerDoorOpen() As Boolean
        Get

            Return innerDoorOpenValue
        End Get
        Set(ByVal value As Boolean)
            If (value & outerDoorOpenValue) Then
                Throw New Exception("Cannot open both doors!")
            Else
                innerDoorOpenValue = value
            End If
        End Set
    End Property

    Public Property OuterDoorOpen() As Boolean
        Get
            Return outerDoorOpenValue
        End Get
        Set(ByVal value As Boolean)
            If (value & innerDoorOpenValue) Then
                Throw New Exception("Cannot open both doors!")
            Else
                outerDoorOpenValue = value
            End If
        End Set
    End Property
End Class

Penyerang dapat mengirim pesan berbahaya seperti ini, mengatasi batasan dan memasukkan objek ke dalam keadaan tidak valid, yang mungkin memiliki konsekuensi yang tidak diinginkan dan tidak dapat diprediksi.

<SpaceStationAirlock>
    <innerDoorOpen>true</innerDoorOpen>
    <outerDoorOpen>true</outerDoorOpen>
</SpaceStationAirlock>

Situasi ini dapat dihindari dengan mengetahui poin-poin berikut:

  • Saat DataContractSerializer membatalkan serialisasi sebagian besar kelas, konstruktor tidak berjalan. Oleh karena itu, jangan mengandalkan manajemen status apa pun yang dilakukan di konstruktor.

  • Gunakan panggilan balik untuk memastikan bahwa objek dalam status valid. Panggilan balik yang ditandai dengan atribut OnDeserializedAttribute sangat berguna karena berjalan setelah deserialisasi selesai dan memiliki kesempatan untuk memeriksa dan memperbaiki status keseluruhan. Untuk informasi selengkapnya tentang panggilan balik, lihat Panggilan Balik Serialisasi Toleran Versi.

  • Jangan merancang jenis kontrak data untuk mengandalkan urutan tertentu di mana setter properti harus dipanggil.

  • Berhati-hatilah menggunakan jenis warisan yang ditandai dengan atribut SerializableAttribute. Banyak dari mereka dirancang untuk bekerja dengan .NET Framework jarak jauh untuk digunakan hanya dengan data tepercaya. Jenis yang ada yang ditandai dengan atribut ini mungkin belum dirancang dengan mempertimbangkan keamanan status.

  • Jangan mengandalkan properti IsRequired dari atribut DataMemberAttribute untuk menjamin keberadaan data sejauh menyangkut keamanan negara. Data selalu bisa berupa null, zero, atau invalid.

  • Jangan pernah memercayai grafik objek yang dideserialisasi dari sumber data yang tidak tepercaya tanpa memvalidasinya terlebih dahulu. Setiap objek individu mungkin dalam keadaan konsisten, tetapi objek grafik secara keseluruhan mungkin tidak. Selain itu, bahkan jika mode pelestarian grafik objek dinonaktifkan, grafik yang dideserialisasi mungkin memiliki beberapa referensi ke objek yang sama atau memiliki referensi melingkar. Untuk informasi selengkapnya, lihat Serialisasi dan Deserialisasi.

Menggunakan NetDataContractSerializer Dengan Aman

NetDataContractSerializer adalah mesin serialisasi yang menggunakan kopling ketat untuk mengetik. Ini mirip dengan BinaryFormatter dan SoapFormatter. Artinya, ini menentukan jenis mana yang akan diinstansiasi dengan membaca rakitan .NET Framework dan mengetik nama dari data masuk. Meskipun ini adalah bagian dari WCF, tidak ada cara yang disediakan untuk mencolokkan mesin serialisasi ini; kode kustom harus ditulis. NetDataContractSerializer disediakan terutama untuk memudahkan migrasi dari .NET Framework jarak jauh ke WCF. Untuk informasi selengkapnya, lihat bagian yang relevan di Serialisasi dan Deserialisasi.

Karena pesan itu sendiri mungkin menunjukkan jenis apa pun dapat dimuat, mekanisme NetDataContractSerializer pada dasarnya tidak aman dan harus digunakan hanya dengan data tepercaya. Untuk informasi selengkapnya, lihat panduan keamanan BinaryFormatter.

Bahkan saat digunakan dengan data tepercaya, data yang masuk mungkin tidak cukup menentukan jenis yang akan dimuat, terutama jika properti AssemblyFormat disetel ke Simple. Siapa pun yang memiliki akses ke direktori aplikasi atau ke cache perakitan global dapat menggantikan jenis berbahaya sebagai pengganti yang seharusnya dimuat. Selalu pastikan keamanan direktori aplikasi Anda dan cache perakitan global dengan mengatur izin dengan benar.

Secara umum, jika Anda mengizinkan akses kode yang sebagian tepercaya ke instans NetDataContractSerializer Anda atau dengan cara lain mengontrol pemilih pengganti (ISurrogateSelector) atau pengikat serialisasi (SerializationBinder), kode dapat melakukan banyak kontrol atas serialisasi/ proses deserialisasi. Misalnya, ini dapat menyuntikkan jenis arbitrer, menyebabkan pengungkapan informasi, mengubah grafik objek yang dihasilkan atau data berseri, atau meluapkan aliran serial yang dihasilkan.

Masalah keamanan lain dengan NetDataContractSerializer adalah penolakan layanan, bukan ancaman eksekusi kode berbahaya. Saat menggunakan NetDataContractSerializer, selalu setel kuota MaxItemsInObjectGraph ke nilai aman. Sangat mudah untuk membuat pesan berbahaya kecil yang mengalokasikan array objek yang ukurannya hanya dibatasi oleh kuota ini.

XmlSerializer-Specific Threats

Model keamanan XmlSerializer mirip dengan DataContractSerializer. Namun, beberapa ancaman unik untuk XmlSerializer.

XmlSerializer menghasilkan rakitan serialisasi pada waktu proses yang berisi kode yang sebenarnya membuat serial dan deserialize; rakitan ini dibuat di direktori file sementara. Jika beberapa proses atau pengguna lain memiliki hak akses ke direktori tersebut, mereka dapat menimpa kode serialisasi/deserialisasi dengan kode arbitrer. XmlSerializer kemudian menjalankan kode ini menggunakan konteks keamanannya, bukan kode serialisasi/deserialisasi. Pastikan izin diatur dengan benar pada direktori file sementara untuk mencegah hal ini terjadi.

XmlSerializer juga memiliki mode yang menggunakan rakitan serialisasi yang dibuat sebelumnya dan bukan membuatnya saat dijalankan. Mode ini dipicu setiap kali XmlSerializer dapat menemukan rakitan serialisasi yang sesuai. XmlSerializer memeriksa apakah rakitan serialisasi ditandatangani oleh kunci yang sama yang digunakan untuk menandatangani rakitan yang berisi jenis yang sedang diserialisasikan atau tidak. Ini menawarkan perlindungan dari rakitan berbahaya yang disaring sebagai rakitan serialisasi. Namun, jika rakitan yang berisi jenis serialisasi Anda tidak ditandatangani, XmlSerializer tidak dapat melakukan pemeriksaan ini dan menggunakan perakitan apa pun dengan nama yang benar. Ini memungkinkan menjalankan kode berbahaya. Selalu tanda tangani rakitan yang berisi jenis serialisasi Anda, atau kontrol akses ketat ke direktori aplikasi Anda dan cache perakitan global untuk mencegah pengenalan rakitan berbahaya.

XmlSerializer dapat terkena penolakan serangan layanan. XmlSerializer tidak memiliki kuota MaxItemsInObjectGraph (seperti yang tersedia di DataContractSerializer). Dengan demikian, ia mendeserialisasi jumlah objek arbitrer, hanya dibatasi oleh ukuran pesan.

Ancaman Kepercayaan Parsial

Perhatikan kekhawatiran berikut mengenai ancaman yang terkait dengan kode yang berjalan dengan kepercayaan parsial. Ancaman ini termasuk kode berbahaya yang dipercaya sebagian serta kode yang dipercaya sebagian berbahaya dalam kombinasi dengan skenario serangan lainnya (misalnya, kode yang dipercaya sebagian yang membangun string tertentu dan kemudian mendeserialisasinya).

  • Saat menggunakan komponen serialisasi apa pun, jangan pernah menegaskan izin apa pun sebelum penggunaan tersebut, bahkan jika seluruh skenario serialisasi berada dalam cakupan pernyataan Anda, dan Anda tidak berurusan dengan data atau objek yang tidak tepercaya. Penggunaan tersebut dapat menyebabkan kerentanan keamanan.

  • Dalam kasus di mana kode yang dipercaya sebagian memiliki kontrol atas proses serialisasi, baik melalui titik ekstensibilitas (pengganti), jenis yang diserialisasikan, atau melalui cara lain, kode yang dipercaya sebagian dapat menyebabkan serializer menghasilkan sejumlah besar data ke dalam aliran berseri, yang dapat menyebabkan Penolakan Layanan (DoS) ke penerima aliran ini. Jika Anda membuat serial data yang ditujukan untuk target yang sensitif terhadap ancaman DoS, jangan membuat serial dengan tipe yang dipercaya sebagian atau sebaliknya biarkan kode yang sebagian dipercaya mengontrol serialisasi.

  • Jika Anda mengizinkan akses kode yang sebagian tepercaya ke instans DataContractSerializer Anda atau dengan cara lain mengontrol Pengganti Kontrak Data, itu mungkin melakukan banyak kontrol atas proses serialisasi/deserialisasi. Misalnya, ini dapat menyuntikkan jenis arbitrer, menyebabkan pengungkapan informasi, mengubah grafik objek yang dihasilkan atau data berseri, atau meluapkan aliran serial yang dihasilkan. Ancaman NetDataContractSerializer yang setara dijelaskan di bagian "Menggunakan NetDataContractSerializer dengan Aman".

  • Jika atribut DataContractAttribute diterapkan ke suatu tipe (atau tipe yang ditandai sebagai SerializableAttribute tetapi bukan ISerializable), deserializer dapat membuat turunan dari tipe tersebut meskipun semua konstruktor nonpublik atau dilindungi berdasarkan permintaan.

  • Jangan pernah memercayai hasil deserialisasi kecuali data yang akan dideserialisasi dipercaya dan Anda yakin bahwa semua jenis yang diketahui adalah jenis yang Anda percayai. Perhatikan bahwa jenis yang diketahui tidak dimuat dari file konfigurasi aplikasi, (tetapi dimuat dari file konfigurasi komputer) saat berjalan dalam kepercayaan parsial.

  • Jika Anda meneruskan instans DataContractSerializer dengan pengganti yang ditambahkan ke kode yang tepercaya sebagian, kode dapat mengubah pengaturan yang dapat dimodifikasi pada pengganti tersebut.

  • Untuk objek yang dideserialisasi, jika pembaca XML (atau data di dalamnya) berasal dari kode yang tepercaya sebagian, perlakukan objek yang dideserialisasi yang dihasilkan sebagai data yang tidak tepercaya.

  • Fakta bahwa jenis ExtensionDataObject tidak memiliki anggota publik tidak berarti bahwa data di dalamnya aman. Misalnya, jika Anda melakukan deserialisasi dari sumber data yang diistimewakan menjadi objek tempat beberapa data berada, lalu menyerahkan objek itu ke kode yang dipercaya sebagian, kode yang dipercaya sebagian dapat membaca data di ExtensionDataObject dengan membuat serial objek. Pertimbangkan pengaturan IgnoreExtensionDataObject ke true saat deserialisasi dari sumber data istimewa ke dalam objek yang kemudian diteruskan ke kode yang dipercaya sebagian.

  • DataContractSerializer dan DataContractJsonSerializer mendukung serialisasi anggota pribadi, dilindungi, internal, dan publik dengan kepercayaan penuh. Namun, dalam kepercayaan parsial, hanya anggota publik yang dapat diserialisasikan. SecurityException dilemparkan jika aplikasi mencoba membuat serial anggota nonpublik.

    Untuk mengizinkan anggota internal atau internal yang dilindungi untuk diserialkan dalam kepercayaan sebagian, gunakan atribut rakitan InternalsVisibleToAttribute. Atribut ini memungkinkan rakitan untuk menyatakan bahwa anggota internalnya terlihat oleh beberapa rakitan lainnya. Dalam hal ini, perakitan yang ingin anggota internalnya diserialisasikan menyatakan bahwa anggota internalnya terlihat untuk System.Runtime.Serialization.dll.

    Keuntungan dari pendekatan ini adalah tidak memerlukan jalur pembuatan kode yang ditinggikan.

    Pada saat yang sama, ada dua kerugian besar.

    Kerugian pertama adalah bahwa properti keikutsertaan dari atribut InternalsVisibleToAttribute bersifat perakitan. Artinya, Anda tidak dapat menentukan bahwa hanya kelas tertentu yang dapat membuat anggota internalnya diserialisasikan. Tentu saja, Anda masih dapat memilih untuk tidak membuat serial anggota internal tertentu, hanya dengan tidak menambahkan atribut DataMemberAttribute ke anggota tersebut. Demikian pula, pengembang juga dapat memilih untuk membuat anggota internal daripada privat atau terlindungi, dengan sedikit masalah visibilitas.

    Kerugian kedua adalah masih tidak mendukung anggota privat atau terlindungi.

    Untuk mengilustrasikan penggunaan atribut InternalsVisibleToAttribute dalam kepercayaan parsial, pertimbangkan program berikut:

        public class Program
        {
            public static void Main(string[] args)
            {
                try
                {
    //              PermissionsHelper.InternetZone corresponds to the PermissionSet for partial trust.
    //              PermissionsHelper.InternetZone.PermitOnly();
                    MemoryStream memoryStream = new MemoryStream();
                    new DataContractSerializer(typeof(DataNode)).
                        WriteObject(memoryStream, new DataNode());
                }
                finally
                {
                    CodeAccessPermission.RevertPermitOnly();
                }
            }
    
            [DataContract]
            public class DataNode
            {
                [DataMember]
                internal string Value = "Default";
            }
        }
    

    Dalam contoh di atas, PermissionsHelper.InternetZone sesuai dengan PermissionSet untuk kepercayaan sebagian. Sekarang, tanpa atribut InternalsVisibleToAttribute, aplikasi akan gagal, memunculkan SecurityException yang menunjukkan bahwa anggota nonpublik tidak dapat diserialisasi dalam kepercayaan parsial.

    Namun, jika kita menambahkan baris berikut ke file sumber, program berhasil dijalankan.

    [assembly:System.Runtime.CompilerServices.InternalsVisibleTo("System.Runtime.Serialization, PublicKey = 00000000000000000400000000000000")]
    

Masalah Manajemen Status Lainnya

Beberapa kekhawatiran lain mengenai manajemen status objek layak disebutkan:

  • Saat menggunakan model pemrograman berbasis aliran dengan transportasi streaming, pemrosesan pesan terjadi saat pesan tiba. Pengirim pesan dapat membatalkan operasi pengiriman di tengah aliran, meninggalkan kode Anda dalam status yang tidak dapat diprediksi jika lebih banyak konten diharapkan. Secara umum, jangan mengandalkan aliran yang selesai, dan tidak melakukan pekerjaan apa pun dalam operasi berbasis aliran yang tidak dapat digulung balik jika aliran dibatalkan. Ini juga berlaku untuk situasi di mana pesan mungkin cacat setelah isi streaming (misalnya, mungkin kehilangan tag akhir untuk amplop SOAP atau mungkin memiliki isi pesan kedua).

  • Menggunakan fitur IExtensibleDataObject ini dapat menyebabkan data sensitif dipancarkan. Jika Anda menerima data dari sumber yang tidak tepercaya ke dalam kontrak data dengan IExtensibleObjectData dan kemudian memancarkannya kembali pada saluran aman tempat pesan ditandatangani, Anda berpotensi menjamin data yang tidak Anda ketahui sama sekali. Selain itu, status keseluruhan yang Anda kirim mungkin tidak valid jika Anda mempertimbangkan potongan data yang diketahui dan tidak diketahui. Hindari situasi ini dengan secara selektif mengatur properti data ekstensi ke null atau dengan menonaktifkan fitur IExtensibleObjectData secara selektif.

Impor Skema

Biasanya, proses mengimpor skema untuk menghasilkan tipe hanya terjadi pada waktu desain, misalnya, saat menggunakan Alat Utilitas Metadata ServiceModel (Svcutil.exe) pada layanan Web untuk menghasilkan kelas klien. Namun, dalam skenario yang lebih canggih, Anda dapat memproses skema pada durasi. Ketahuilah bahwa melakukannya dapat mengekspos Anda terhadap risiko penolakan layanan. Beberapa skema mungkin membutuhkan waktu lama untuk diimpor. Jangan pernah menggunakan komponen impor skema XmlSerializer dalam skenario seperti itu jika skema mungkin berasal dari sumber yang tidak tepercaya.

Ancaman Khusus untuk integrasi AJAX ASP.NET

Saat pengguna mengimplementasikan WebScriptEnablingBehavior atau WebHttpBehavior, WCF mengekspos titik akhir yang dapat menerima pesan XML dan JSON. Namun, hanya ada satu set kuota pembaca, yang digunakan oleh pembaca XML dan pembaca JSON. Beberapa pengaturan kuota mungkin sesuai untuk satu pembaca tetapi terlalu besar untuk yang lain.

Saat menerapkan WebScriptEnablingBehavior, pengguna memiliki opsi untuk mengekspos proksi JavaScript di titik akhir. Masalah keamanan berikut harus dipertimbangkan:

  • Informasi tentang layanan (nama operasi, nama parameter, dan sebagainya) dapat diperoleh dengan memeriksa proksi JavaScript.

  • Saat menggunakan titik akhir JavaScript, informasi sensitif dan privat mungkin disimpan di cache browser Web klien.

Catatan tentang Komponen

WCF adalah sistem yang fleksibel dan dapat disesuaikan. Sebagian besar konten topik ini berfokus pada skenario penggunaan WCF yang paling umum. Namun, dimungkinkan untuk menyusun komponen yang disediakan WCF dengan berbagai cara. Penting untuk memahami implikasi keamanan menggunakan setiap komponen. Secara khusus:

  • Ketika Anda harus menggunakan pembaca XML, gunakan pembaca XmlDictionaryReader yang disediakan kelas dibandingkan dengan pembaca lain. Pembaca aman dibuat menggunakan metode CreateTextReader, CreateBinaryReader, atau CreateMtomReader. Jangan gunakan metode Create. Selalu konfigurasikan pembaca dengan kuota yang aman. Mesin serialisasi di WCF hanya aman ketika digunakan dengan pembaca XML aman dari WCF.

  • Saat menggunakan DataContractSerializer untuk mendeserialisasi data yang berpotensi tidak tepercaya, selalu atur properti MaxItemsInObjectGraph.

  • Saat membuat pesan, setel parameter maxSizeOfHeaders jika MaxReceivedMessageSize tidak menawarkan perlindungan yang memadai.

  • Saat membuat pembuat enkode, selalu konfigurasikan kuota yang relevan, seperti MaxSessionSize dan MaxBufferSize.

  • Saat menggunakan filter pesan JalurX, atur NodeQuota untuk membatasi jumlah simpul XML yang dikunjungi filter. Jangan gunakan ekspresi JalurX yang bisa memakan waktu lama untuk menghitung tanpa mengunjungi banyak simpul.

  • Secara umum, saat menggunakan komponen apa pun yang menerima kuota, pahami implikasi keamanannya dan atur ke nilai yang aman.

Lihat juga