On Reflection defeating encapsulation & how to prevent Reflection from accessing private fields

Ini sebenarnya isu lama, bahkan om A.K. sudah mem-posting di tahun 2005, Reflection Sebagai Penjahat Perang Pelanggar OO. Saya sempat menaruh comment disana tapi mungkin tidak meng-elaborasinya… jadi saya mau bikin ini permanen di blog biar next time ada yg tanya bisa nyampe kesini via Google Live.

Anyway awalnya begini seminggu yg lalu…Di tempat saya consulting ada rekan yang iseng-iseng melemparkan quiz hari Jumat… kira-kira begini pertanyaannya:

Ada class A yg hanya berisi private field tanpa public mekanisme (public setter atau public method). Kemudian ada class B yang tidak inherit dari class A namun meng-agregat class A tadi. Bisakah class B ini mengubah private field class A tadi?

Kemudian saya memperhatikan ping-pong email yg intinya mengingatkan pada teori OOP tentang Encapsulation.

Kemudian akhirnya quiz ditutup dengan jawaban simple: TIDAK_BISA.

Karena saya orangnya suka melawan arus hehehe… maka saya gatal untuk memencet Reply-to-All dan mengetik opini berikut:

--- start of message ---

Bos, kalo di .NET ini BISA… coba jalankan source code berikut:

  1: public static class ReflectionMagic
  2: {
  3:     public static void ModifyPrivateMember(object instance, 
  4:                                            string memberName, 
  5:                                            object newValue)
  6:     {
  7:         Type t = instance.GetType();
  8:         System.Reflection.FieldInfo f = t.GetField(memberName,
  9:                                           BindingFlags.Instance 
 10:                                           | BindingFlags.NonPublic
 11:                                           );
 12:         f.SetValue(instance, newValue);
 13:     }
 14: }
 15: 
 16: public class A
 17: {
 18:     private string _password;
 19: }
 20: 
 21: [TestFixture]
 22: public class B
 23: {
 24:     [Test]
 25:     public void TestQuiz()
 26:     {
 27:         A newA = new A();
 28: 
 29:         ReflectionMagic.ModifyPrivateMember(newA, "_password", "I_Changed_Your_Password");
 30:     }
 31: }

Ini screenshot hasil debugger, sebelum masuk ke kode ReflectionMagic:

ScreenShot027

Dan ini sesudah keluar dari kode ReflectionMagic:

ScreenShot028

--- end of message ---

  

Kegunaan readonly Reflection

Dan setelah email ini dikirim, mulailah muncul pertanyaan ttg apa gunanya punya private field kalo ternyata bisa “diakalin” juga… dan juga tentang kegunaan Reflection ini.

Hmm, menurut saya kemampuan inspeksi object secara runtime sangat powerful untuk pembuat utility/tools. Misal, Class View di Visual Studio ga bakal bisa jalan kalo nggak ada Reflection.

Secara personal, saya menggunakan Reflection untuk membuat VS2003 add-ins Refactor-Z dan UML Class Diagram Generator (separate note: yg kemudian tidak dikembangkan lebih lanjut gara2 di VS2005 udah ada fitur untuk “Surround Code with…” dan ada WhiteHorse atau klik kanan View Class Diagram).

Jadi reflection bagus untuk pembuat tools yg butuh menampilkan data-data object sewaktu runtime.

  

Kegunaan writeable Reflection

Tapi muncul pertanyaan, “lantas apa gunanya FieldInfo.SetValue ? Jika Anda hanya membuat tools untuk menampilkan data-data object sewaktu runtime kan bisa dengan FieldInfo.GetValue … buat apa MS ngasih SetValue?”

Well… kalo kasus ini saya belum pernah buat tool yg menggunakan SetValue sih… tapi biasanya fungsi ini digunakan untuk Data Transformation dan Mapping Tool (versi awal tool-tool ORM seperti Hibernate sepertinya menggunakan ini).

  

Cara Proteksi Private Field dari GetValue/SetValue

At the end of the day, pertanyaannya adalah “bisa nggak proteksi private fields class gw dari Reflection?”

Yo uwis kalo gitu, jawabannya bisa, dan tinggal tambahin kode ini sebelum kode namespace…

  1: using System;
  2: using System.Reflection ;
  3: using System.Security.Permissions ;
  4: using NUnit.Framework ;
  5: 
  6: [assembly: ReflectionPermissionAttribute(
  7:  SecurityAction.RequestRefuse,
  8:  Unrestricted = true)]
  9: 
 10: namespace ReflectionTests
 11: {
 12:     public static class ReflectionMagic
 13:     {
 14:       ...

Hasilnya adalah seperti berikut… GetValue akan menghasilkan FieldAccessException:

fieldexception

Dan SetValue pun akan tidak berhasil mengubah private field kita:

ScreenShot029

 

Next time saya akan ngomongin tentang Code Signing deh… tidak berhubungan dgn Reflection, tapi masih dalam berhubungan dengan topik “membuktikan kode Anda belum pernah dimodifikasi orang lain” dan “membuktikan kode Anda benar-benar berasal dari Anda”.

Share this post: | | | |
Published Monday, March 09, 2009 9:45 PM by zeddy
Filed under: ,

Comments

# re: On Reflection defeating encapsulation & how to prevent Reflection from accessing private fields

Tuesday, March 10, 2009 6:57 AM by ridi

udah lama... ndak dengar tentang Reflection.. tapi di ujian MCTS keluar tuh 2-3 nomor :p

# re: On Reflection defeating encapsulation & how to prevent Reflection from accessing private fields

Tuesday, March 10, 2009 7:20 AM by yulian

Nice article bos Z :) ujung2nya harus ngerti CAS baik itu secara declarative maupun imperative :)

# re: On Reflection defeating encapsulation & how to prevent Reflection from accessing private fields

Tuesday, March 10, 2009 12:42 PM by cahnom

Mantab... thanks untuk sharing ilmunya

# re: On Reflection defeating encapsulation & how to prevent Reflection from accessing private fields

Tuesday, March 10, 2009 4:00 PM by Pingky Dezar

Wah... salah dong selama ini gw kalo ngajar pas di materi OOP..  :-p

Pokoknya mantab dah tulisannya

# re: On Reflection defeating encapsulation & how to prevent Reflection from accessing private fields

Sunday, March 29, 2009 3:12 PM by ronaldwidha

Great Post

Satu lagi dari Microsoft! haha

Microsoft memang selalu punya reputasi untuk menyediakan tool2 yang sangat powerful tapi dengan konsekuen menjauhkan penggunanya dari the pitfall of success.

Salah satu kegunaan reflection yang paling umum adalah untuk plugin architecture. Sebelum the upcoming Managed Extensibility Framework, kita harus melakukan reflection untuk menginterogasi dll di sebuah folder dan mencari untuk tipe interface tertentu.

Powered by Community Server (Commercial Edition), by Telligent Systems