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 pihak 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 masuk menyebabkan sisi penerima menjalankan kode yang tidak diinginkannya.

  • Pengungkapan informasi

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

User-Provided Kode dan Keamanan Akses Kode

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

Penulis kode bertanggung jawab untuk memastikan bahwa tidak ada kerentanan keamanan. Misalnya, jika Anda membuat jenis kontrak data dengan properti anggota data dari jenis bilangan bulat, dan dalam implementasi aksesor set mengalokasikan array berdasarkan nilai properti, Anda membuka kemungkinan serangan penolakan layanan jika pesan berbahaya mengandung 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. (Kondisi OutOfMemoryException tidak dapat dipulihkan dalam .NET Framework dan selalu menyebabkan penghentian aplikasi Anda.)

Anda harus memastikan bahwa tidak ada kode berbahaya yang dicolokkan ke berbagai titik ekstensibilitas. Ini sangat relevan ketika dijalankan di bawah kepercayaan parsial, berurusan dengan tipe dari rakitan dengan kepercayaan 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 atau jenis data privat yang menggunakan SerializableAttribute atribut tidak didukung. Untuk informasi selengkapnya, lihat Kepercayaan Parsial.

Nota

Keamanan Akses Kode (CAS) telah 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 DataContractSerializer pemrograman memungkinkan paparan data privat dan internal di luar tipe atau assembly selama serialisasi. Selain itu, struktur jenis dapat ditampilkan selama ekspor skema. Pastikan untuk memahami proyeksi serialisasi jenis tersebut. Jika Anda tidak ingin sesuatu terekspos, nonaktifkan serialisasi (misalnya, dengan tidak menerapkan DataMemberAttribute atribut dalam kasus kontrak data).

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

  • Menggunakan XmlSerializer dalam pemanggilan prosedur jarak jauh (RPC)/mode yang dikodekan dapat secara tidak sengaja memperlihatkan bentuk struktur objek di sisi pengirim kepada sisi penerima.

Mencegah Serangan Penolakan Layanan

Kuota

Menyebabkan pihak penerima harus mengalokasikan sejumlah besar memori dapat menjadi 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, QuotaExceededException pengecualian biasanya dilemparkan. Tanpa kuota, pesan berbahaya dapat menyebabkan seluruh memori yang tersedia diakses, yang menghasilkan pengecualian, atau seluruh tumpukan yang tersedia diakses, yang menghasilkan OutOfMemoryException.

Skenario terlampaui kuota dapat dipulihkan; jika ditemui dalam layanan yang sedang berjalan, pesan yang saat ini sedang diproses dibuang dan layanan terus berjalan dan memproses pesan lebih lanjut. Skenario out-of-memory dan stack overflow tidak dapat dipulihkan di bagian mana pun dari .NET Framework; layanan akan dihentikan jika mengalami pengecualian tersebut.

Kuota dalam WCF tidak melibatkan pra-alokasi. Misalnya, jika MaxReceivedMessageSize kuota (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 pada 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 rinci 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. Kehati-hatian harus dilakukan saat menetapkan kuota ini untuk mencegah serangan tersebut. Kuota ini menempatkan batas atas pada ukuran pesan WCF. Selain itu, hindari menggunakan tabel hash 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 tanpa streaming, pesan dimuat ke dalam memori. Dalam hal ini, gunakan MaxReceivedMessageSize kuota pada TransportBindingElement atau pada pengikatan yang disediakan sistem untuk melindungi dari pesan berukuran besar dengan membatasi ukuran maksimum pesan yang dapat diterima. Perhatikan bahwa layanan mungkin memproses beberapa pesan secara bersamaan, dalam hal ini semuanya dalam memori. Gunakan fitur pengendalian 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 menampung grafik objek yang dideserialisasi, mengakibatkan konsumsi memori total melebihi 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. Masalah ini diperparah ketika jenis tersebut adalah bagian dari array.

MaxReceivedMessageSize saja tidak cukup untuk mencegah semua serangan penolakan layanan. Misalnya, deserializer dapat dipaksa untuk mendeserialisasi grafik objek yang sangat berlapis (objek yang berisi objek lain yang berisi objek lain, dan sebagainya) oleh pesan masuk. Baik metode DataContractSerializer maupun XmlSerializer memanggil dengan cara berlapis untuk mendeserialisasi grafik tersebut. Bersarang dalam panggilan metode dapat mengakibatkan tidak dapat dipulihkan StackOverflowException. Ancaman ini diatasi dengan mengatur kuota MaxDepth untuk membatasi tingkat pelesapan XML, seperti yang dibahas di bagian "Menggunakan XML Dengan Aman" nanti dalam topik.

Mengatur kuota tambahan menjadi 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. Dengan demikian, bahkan pesan yang sesuai dengan batas ukuran MaxReceivedMessageSize dapat memakan lebih banyak memori dalam bentuk yang benar-benar diperluas. 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 kecil MaxReceivedMessageSize 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 aliran pesan langsung ke disk. Jika pesan berbahaya entah bagaimana dapat memaksa WCF untuk menyangga data alih-alih mengalirkannya dalam hal ini, MaxReceivedMessageSize tidak lagi melindungi terhadap 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 binding transport dan binding standar. Saat streaming, kuota ini harus diatur dengan mempertimbangkan jumlah maksimum memori yang ingin Anda alokasikan per pesan. MaxReceivedMessageSizeSeperti halnya , pengaturan tidak menempatkan maksimum absolut pada konsumsi memori tetapi hanya membatasinya dalam faktor konstan. Seperti halnya MaxReceivedMessageSize, waspadai kemungkinan beberapa pesan diproses secara bersamaan.

Detail MaxBufferSize

Properti MaxBufferSize membatasi buffering massal yang dilakukan WCF. Misalnya, WCF selalu buffer header SOAP dan kesalahan SOAP, serta bagian MIME apa pun yang ditemukan tidak dalam urutan baca 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 dapat menampung sementara. Misalnya, beberapa overload CreateMessage dari kelas Message menggunakan parameter maxSizeOfHeaders. WCF mengoper nilai MaxBufferSize ke parameter ini untuk membatasi buffer header SOAP. Penting untuk mengatur parameter ini secara langsung saat menggunakan kelas Message. Secara umum, saat menggunakan komponen dalam WCF yang mengambil parameter kuota, penting untuk memahami implikasi keamanan parameter ini dan mengaturnya dengan benar.

Encoder pesan MTOM juga memiliki pengaturan MaxBufferSize. Saat menggunakan pengikatan standar, ini diatur secara otomatis ke nilai tingkat MaxBufferSize transportasi. Namun, saat menggunakan elemen pengikatan encoder pesan MTOM untuk membangun pengikatan kustom, penting untuk mengatur MaxBufferSize properti ke nilai aman saat streaming digunakan.

Serangan Streaming XML-Based

MaxBufferSize saja tidak cukup untuk memastikan agar WCF tidak dipaksa untuk buffering di saat diharapkan streaming. Misalnya, pembaca XML WCF selalu buffer seluruh tag mulai elemen XML saat mulai membaca elemen baru. Ini dilakukan agar namespace 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 streaming dan pemrograman non-streaming dalam layanan yang sama. Misalkan ada kontrak layanan dengan dua operasi: satu mengambil Stream dan yang lainnya mengambil array dari beberapa tipe khusus. Misalkan juga yang MaxReceivedMessageSize diatur 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 menyimpan data dalam memori sebagai array sebelum operasi dipanggil. Ini adalah potensi serangan penolakan layanan (denial-of-service): MaxBufferSize kuota tidak membatasi ukuran isi pesan, yang digunakan oleh deserializer.

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

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

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

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

  • Tinjau daftar jenis-jenis yang sudah diketahui, perlu diingat bahwa salah satu dari jenis tersebut dapat diinstansiasi kapan saja (silakan lihat bagian "Mencegah Pemuatan Jenis yang Tidak Diinginkan" yang akan dibahas lebih lanjut dalam topik ini).

  • Jangan gunakan jenis apa pun yang mengimplementasikan antarmuka IXmlSerializable yang menyimpan sementara banyak data. Jangan tambahkan jenis tersebut ke daftar jenis yang diketahui.

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

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

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

Serangan Aliran Pelan

Kelas serangan penolakan layanan streaming tidak melibatkan konsumsi memori. Sebaliknya, serangan melibatkan pengirim lambat atau penerima data. 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 selengkapnya, lihat Kuota Transportasi. Kedua, jangan pernah menggunakan operasi sinkron Read atau Write saat bekerja dengan aliran di WCF.

Menggunakan XML Dengan Aman

Nota

Meskipun bagian ini tentang XML, informasi juga berlaku untuk dokumen JavaScript Object Notation (JSON). Kuota berfungsi 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 di WCF (teks, biner, atau MTOM).

Beberapa fitur keamanan pada pembaca tersebut 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 langsung dengan pembaca XML (seperti saat menulis encoder kustom Anda sendiri atau saat bekerja langsung dengan Message kelas ), selalu gunakan pembaca aman WCF ketika ada kemungkinan untuk bekerja dengan data yang tidak tepercaya. Buat pembaca yang aman dengan memanggil salah satu metode pabrik statis overload CreateTextReader, CreateBinaryReader, atau CreateMtomReader pada kelas XmlDictionaryReader. Saat membuat pembaca data, masukkan nilai kuota yang aman. Jangan panggil metode kelebihan Create beban. Ini tidak membuat pembaca WCF. Sebagai gantinya, dibuat sebuah pembaca yang tidak dilindungi oleh fitur keamanan yang dijelaskan sebelumnya di bagian ini.

Kuota Pembaca

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

MaxBytesPerRead

Kuota ini membatasi jumlah byte yang dibaca dalam satu Read operasi saat membaca tag mulai elemen dan atributnya. (Dalam kasus yang tidak dialirkan, nama elemen itu sendiri tidak dihitung terhadap kuota.) MaxBytesPerRead penting untuk 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 ketika streaming diharapkan. Lihat bagian MaxDepth kuota untuk informasi tentang jumlah buffering aktual yang terjadi.

  • Memiliki terlalu banyak atribut XML dapat menggunakan waktu pemrosesan yang tidak proporsional karena nama atribut harus diperiksa keunikannya. MaxBytesPerRead mengurangi ancaman ini.

Kedalaman Maksimum

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

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

  • Saat mendeserialisasi grafik objek yang sangat bersarang, deserializer dipaksa untuk mengakses seluruh tumpukan dan melemparkan yang tidak dapat dipulihkan StackOverflowException. Korelasi langsung ada antara xml bersarang dan objek bersarang untuk DataContractSerializer dan XmlSerializer. Gunakan MaxDepth untuk mengurangi ancaman ini.

MaxNameTableCharCount

Kuota ini membatasi ukuran nametable pembaca. Nametable berisi string tertentu (seperti namespace dan awalan) yang ditemui 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 dikembalikan pembaca XML. Kuota ini tidak membatasi konsumsi memori di pembaca XML itu sendiri, tetapi dalam komponen yang menggunakan pembaca. Misalnya, jika DataContractSerializer menggunakan pembaca yang diamankan dengan MaxStringContentLength, maka string yang lebih besar dari kuota ini tidak akan dideserialisasi. Saat menggunakan XmlDictionaryReader secara langsung, tidak semua metode menghormati kuota ini, tetapi hanya metode yang dirancang khusus untuk membaca string, seperti ReadContentAsString. Properti Value pada pembaca data tidak terpengaruh oleh kuota ini, sehingga sebaiknya tidak digunakan ketika perlindungan yang diberikan oleh kuota ini diperlukan.

MaxArrayLength

Kuota ini membatasi ukuran maksimum dari array tipe dasar yang dikembalikan oleh pembaca XML, termasuk array byte. Kuota ini tidak membatasi konsumsi memori di pembaca XML itu sendiri, tetapi dalam komponen apa pun yang menggunakan pembaca. Misalnya, ketika DataContractSerializer menggunakan pembaca yang diamankan dengan MaxArrayLength, pembaca tersebut tidak akan mendeserialisasi array byte yang ukurannya lebih besar dari kuota ini. Penting untuk mengatur kuota ini saat mencoba mencampur model streaming dan pemrograman buffer dalam satu kontrak. Ingat bahwa saat menggunakan XmlDictionaryReader kelas secara langsung, hanya metode yang dirancang khusus untuk membaca array dengan ukuran sembarang dari jenis primitif tertentu, seperti ReadInt32Array, mematuhi kuota ini.

Ancaman Khusus untuk Pengodean Biner

Pengodean XML biner WCF mendukung 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 bisa memiliki panjang sembarang dan karenanya menimbulkan ancaman yang lebih serius daripada yang ada di dalam kamus statis.

Ancaman pertama yang harus dimitigasi adalah kemungkinan kamus dinamis (tabel pemetaan string-ke-kode) menjadi terlalu besar. Kamus ini dapat diperluas melalui beberapa pesan, dan karena itu MaxReceivedMessageSize kuota tidak menawarkan perlindungan karena hanya berlaku untuk setiap pesan secara terpisah. Oleh karena itu, properti terpisah MaxSessionSize 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 dilemparkan seperti biasa. Jika terlampaui saat menulis pesan, string apa pun yang menyebabkan kuota terlampaui ditulis as-is, tanpa menggunakan fitur kamus dinamis.

Ancaman Terhadap Ekspansi Kamus

Kelas signifikan serangan yang spesifik untuk biner muncul dari pengembangan kamus. Pesan kecil dalam bentuk biner dapat berubah menjadi pesan yang sangat besar dalam bentuk tekstual yang sepenuhnya diperluas jika membuat penggunaan ekstensif dari fitur kamus string. Faktor ekspansi untuk string kamus dinamis dibatasi oleh MaxSessionSize kuota, 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 pra-ekspansi. 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 melakukan 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, nonaktifkan IExtensibleDataObject fitur saat menggunakan pengodean biner. Atur IgnoreExtensionDataObject properti ke true pada ServiceBehaviorAttribute atribut . Atau, jangan terapkan IExtensibleDataObject antarmuka. Untuk informasi selengkapnya, lihat Kontrak DataForward-Compatible.

Ringkasan Kuota

Tabel berikut ini meringkas panduan tentang kuota.

Keadaan Kuota penting untuk ditetapkan
Tidak ada streaming pesan kecil, teks, atau pengodean MTOM. MaxReceivedMessageSize, MaxBytesPerRead, dan MaxDepth
Tidak ada streaming atau pengiriman pesan kecil, enkoding 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 pada level transportasi harus selalu diatur, dan baca/tulis sinkron tidak boleh digunakan saat streaming sedang digunakan, baik Anda sedang melakukan streaming pesan besar maupun 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 yang masuk menyebabkan deserializer membangun instance dari tipe yang biasanya aman dengan cara yang menghasilkan konsekuensi yang tidak diinginkan.

Bagian berikut membahas kelas ancaman ini lebih lanjut.

DataContractSerializer

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

Mencegah Jenis yang Tidak Diinginkan untuk Dimuat

Memuat jenis yang tidak diinginkan mungkin memiliki konsekuensi yang signifikan, apakah jenisnya berbahaya atau hanya memiliki efek samping yang sensitif terhadap keamanan. Tipe mungkin berisi kerentanan keamanan yang dapat dieksploitasi, melakukan tindakan sensitif keamanan di konstruktor atau konstruktor kelasnya, memiliki konsumsi memori besar yang memfasilitasi serangan denial-of-service, atau menimbulkan 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.

DataContractSerializer mendeserialisasikan dengan keterkaitan yang 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. Kopling longgar memperkenalkan tingkat keamanan tertentu, karena penyerang jarak jauh tidak dapat memilih tipe sembarang untuk dimuat hanya dengan menyebutkan tipe tersebut dalam pesan.

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

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

  • KnownTypeAttribute atribut yang diterapkan ke tipe.

  • KnownTypeAttribute atribut yang menentukan metode yang mengembalikan daftar jenis.

  • Atribut ServiceKnownTypeAttribute.

  • Bagian KnownTypes konfigurasi.

  • 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 cakupan, jenis tersebut dapat dimuat kapan saja, dan instans jenis dapat dibuat, bahkan jika kontrak melarang 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 dijalankan.

  • Bahkan saat mendeserialisasi kontrak data dengan anggota data string, pesan berbahaya masih dapat menyebabkan instans MyDangerousType terbentuk. Kode di MyDangerousType, seperti setter properti, mungkin dijalankan. Setelah ini selesai, deserializer mencoba menetapkan instans ini ke anggota data bertipe string dan gagal dengan menghasilkan pengecualian.

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

Jika menentukan jenis konfigurasi yang diketahui, pastikan file konfigurasi aman. Selalu gunakan nama unik yang kuat dalam konfigurasi (dengan menentukan kunci publik dari rakitan yang ditandatangani tempat tipe berada), tetapi jangan tentukan versi tipe yang harus dimuat. Pemuat jenis secara otomatis memilih versi terbaru, jika memungkinkan. Jika Anda menentukan versi tertentu dalam konfigurasi, Anda menghadapi risiko berikut: Tipe mungkin memiliki kerentanan keamanan yang bisa diperbaiki di versi mendatang, tetapi versi yang rentan tetap dimuat karena versi tersebut ditentukan secara eksplisit dalam konfigurasi.

Memiliki terlalu banyak jenis yang diketahui memiliki konsekuensi lain: DataContractSerializer membuat cache kode serialisasi/deserialisasi di dalam domain aplikasi, dengan entri untuk setiap jenis yang harus diserialisasikan dan dideserialisasi. 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 besar yang tidak proporsional.

Mencegah Jenis Berada dalam Status Yang Tidak Diinginkan

Jenis mungkin memiliki batasan konsistensi internal yang harus diberlakukan. Perlu berhati-hati untuk menghindari pelanggaran 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:

  • Ketika DataContractSerializer mendeserialisasi sebagian besar kelas, konstruktor tidak dijalankan. 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 OnDeserializedAttribute atribut sangat berguna karena berjalan setelah deserialisasi selesai dan memiliki kesempatan untuk memeriksa dan memperbaiki status keseluruhan. Untuk informasi selengkapnya, lihat Version-Tolerant Panggilan Balik Serialisasi.

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

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

  • Jangan mengandalkan properti IsRequired dari atribut DataMemberAttribute untuk menjamin keberadaan data dalam hal yang berkaitan dengan keamanan kondisi. Data bisa selalu null, zero, atau invalid.

  • Jangan pernah mempercayai grafik objek yang dideserialisasi dari sumber data yang tidak tepercaya tanpa memvalidasinya terlebih dahulu. Setiap objek individu mungkin dalam keadaan konsisten, tetapi grafik objek 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 keterhubungan erat dengan tipe. 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 remoting .NET Framework ke WCF. Untuk informasi selengkapnya, lihat bagian yang relevan di Serialisasi dan Deserialisasi.

Karena pesan tersebut dapat menunjukkan bahwa sembarang jenis dapat dimuat, mekanisme NetDataContractSerializer tidak aman secara bawaan dan harus digunakan hanya dengan data tepercaya. Untuk informasi selengkapnya, lihat panduan keamanan BinaryFormatter.

Bahkan ketika digunakan dengan data tepercaya, data masuk mungkin tidak cukup menentukan jenis yang akan dimuat, terutama jika AssemblyFormat properti diatur ke Simple. Siapa pun yang memiliki akses ke direktori aplikasi atau ke cache perakitan global dapat mengganti tipe berbahaya sebagai ganti dari 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 tepercaya sebagian ke instans Anda NetDataContractSerializer atau mengontrol pemilih pengganti (ISurrogateSelector) atau binder serialisasi (SerializationBinder), kode dapat menjalankan banyak kontrol atas proses serialisasi/deserialisasi. Misalnya, ini dapat menyuntikkan tipe sembarang, menyebabkan pengungkapan informasi, merusak graf objek yang dihasilkan atau data terserialisasi, atau meluapnya aliran terserialisasi yang dihasilkan.

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

XmlSerializer-Specific Ancaman

Model keamanan XmlSerializer mirip dengan model DataContractSerializer. Beberapa ancaman, bagaimanapun, unik untuk XmlSerializer.

menghasilkan XmlSerializerrakitan serialisasi pada runtime yang berisi kode yang benar-benar menserialisasikan dan mendeserialisasi; rakitan ini dibuat dalam direktori file sementara. Jika beberapa proses atau pengguna lain memiliki hak akses ke direktori tersebut, mereka dapat menimpa kode serialisasi/deserialisasi dengan kode arbitrer. Kemudian XmlSerializer menjalankan kode ini menggunakan konteks keamanannya, alih-alih kode serialisasi/deserialisasi. Pastikan izin disetel dengan benar pada direktori file sementara untuk mencegah hal ini terjadi.

juga XmlSerializer memiliki mode di mana ia menggunakan rakitan serialisasi yang telah dibuat sebelumnya alih-alih menghasilkannya pada waktu proses. Mode ini dipicu setiap kali XmlSerializer dapat menemukan rakitan serialisasi yang sesuai. Pemeriksaan XmlSerializer apakah rakitan serialisasi ditandatangani oleh kunci yang sama yang digunakan untuk menandatangani rakitan yang berisi jenis yang sedang diserialisasikan. Ini menawarkan perlindungan dari rakitan berbahaya yang menyamar sebagai rakitan serialisasi. Namun, jika rakitan yang berisi jenis serializable Anda tidak ditandatangani, XmlSerializer tidak dapat melakukan pemeriksaan ini dan akan menggunakan rakitan apa pun yang memiliki nama yang benar. Ini memungkinkan menjalankan kode berbahaya. Selalu tandatangani aset yang berisi tipe yang dapat diserialkan, atau kontrol akses dengan ketat ke direktori aplikasi Anda dan cache aset global untuk mencegah pengenalan aset berbahaya.

XmlSerializer dapat dikenai serangan penolakan layanan. XmlSerializer tidak memiliki MaxItemsInObjectGraph kuota (seperti yang tersedia pada DataContractSerializer). Dengan demikian, ia mendeserialisasi jumlah objek yang sewenang-wenang, 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 berbahaya yang dipercaya sebagian dalam kombinasi dengan skenario serangan lainnya (misalnya, kode tepercaya 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 mengontrol proses serialisasi, baik melalui titik ekstensibilitas (pengganti), jenis yang diserialisasikan, atau melalui cara lain, kode yang dipercaya sebagian dapat menyebabkan serializer mengeluarkan sejumlah besar data ke dalam aliran berseri, yang dapat menyebabkan Penolakan Layanan (DoS) bagi penerima aliran ini. Jika Anda menserialisasikan data yang ditujukan untuk target yang sensitif terhadap ancaman DoS, jangan melakukan serialisasi jenis yang dipercaya sebagian atau membiarkan kode yang dipercaya sebagian mengontrol proses serialisasi.

  • Jika Anda mengizinkan akses kode dengan tingkat kepercayaan parsial ke instance Anda DataContractSerializer atau mengontrol Data Contract Surrogates, kode tersebut dapat menjalankan kontrol besar atas proses serialisasi/deserialisasi. Misalnya, ini dapat menyuntikkan tipe sembarang, menyebabkan pengungkapan informasi, merusak graf objek yang dihasilkan atau data terserialisasi, atau meluapnya aliran terserialisasi yang dihasilkan. Ancaman yang NetDataContractSerializer setara dijelaskan di bagian "Menggunakan NetDataContractSerializer Dengan Aman".

  • Jika atribut DataContractAttribute diterapkan ke tipe (atau tipe yang ditandai sebagai SerializableAttribute tetapi bukan ISerializable), deserializer dapat membuat instans tipe tersebut bahkan jika semua konstruktor non-publik atau dengan tuntutan keamanan.

  • Jangan pernah mempercayai 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 dijalankan di bawah kepercayaan terbatas.

  • Jika Anda meneruskan instans DataContractSerializer dengan pengganti yang ditambahkan ke lingkungan kode dengan kepercayaan parsial, 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 dipercaya sebagian, perlakukan objek yang dideserialisasi yang dihasilkan sebagai data yang tidak tepercaya.

  • Fakta bahwa jenis ExtensionDataObject ini tidak memiliki anggota publik tidak berarti bahwa data di dalamnya terjamin keamanannya. Misalnya, jika Anda mendeserialisasi dari sumber data istimewa ke dalam objek tempat beberapa data berada, maka serahkan objek tersebut ke kode tepercaya sebagian, kode yang tepercaya sebagian dapat membaca data di dalamnya ExtensionDataObject dengan menserialisasikan objek. Pertimbangkan pengaturan IgnoreExtensionDataObject ke true saat deserialisasi dari sumber data istimewa ke dalam objek yang kemudian diteruskan ke kode tepercaya sebagian.

  • DataContractSerializer dan DataContractJsonSerializer mendukung serialisasi anggota privat, terlindungi, internal, dan publik dengan kepercayaan penuh. Namun, dalam kepercayaan parsial, hanya anggota publik yang dapat diserialisasi. Jika aplikasi mencoba membuat serial anggota non-publik, maka SecurityException akan dilemparkan.

    Untuk memungkinkan anggota internal atau internal terlindungi diserialisasikan dalam kepercayaan terbatas, gunakan atribut assembly InternalsVisibleToAttribute. Atribut ini memungkinkan assembly untuk menyatakan bahwa anggota internalnya dapat diakses oleh assembly lain. Dalam kasus ini, sebuah assembly yang ingin anggota internalnya diserialisasikan menyatakan bahwa anggota internalnya dapat terlihat oleh System.Runtime.Serialization.dll.

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

    Pada saat yang sama, ada dua kelemahan utama.

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

    Kerugian kedua adalah masih tidak mendukung anggota privat atau terlindungi.

    Untuk mengilustrasikan penggunaan InternalsVisibleToAttribute atribut 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 parsial. Sekarang, tanpa atribut InternalsVisibleToAttribute, aplikasi akan mengalami kegagalan, menimbulkan SecurityException yang menunjukkan bahwa anggota non-publik tidak dapat diserialisasikan dalam izin parsial.

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

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

Masalah Pengelolaan Keadaan Lainnya

Beberapa kekhawatiran lain mengenai manajemen status objek patut 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 sudah selesai, dan jangan melakukan pekerjaan apa pun dalam operasi berbasis aliran yang tidak bisa dibatalkan jika aliran tersebut terhenti. Ini juga berlaku untuk situasi di mana pesan mungkin salah bentuk setelah isi streaming (misalnya, mungkin kehilangan tag akhir untuk amplop SOAP atau mungkin memiliki isi pesan kedua).

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

Impor Skema

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

Ancaman Khusus untuk integrasi AJAX ASP.NET

Saat pengguna menerapkan 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. Khususnya:

  • Gunakan pembaca yang disediakan oleh kelas XmlDictionaryReader dibandingkan dengan pembaca lainnya ketika Anda harus menggunakan pembaca XML. Pembaca yang aman dibuat menggunakan CreateTextReadermetode , 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, atur maxSizeOfHeaders parameter jika MaxReceivedMessageSize tidak menawarkan perlindungan yang cukup.

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

  • Saat menggunakan filter pesan XPath, atur NodeQuota untuk membatasi jumlah simpul XML yang dikunjungi filter. Jangan gunakan ekspresi XPath 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