[Part 2] Is c# safe? Readonly fields... Really readonly?

Hi

Today I present you part 2 of "Is c# safe" series. 
Few days ago I though about whether possibility to set value to readonly field outside the constructor.

Quoting the Microsoft website:
"The readonly keyword is a modifier that you can use on fields. When a field declaration includes a readonly modifier, assignments to the fields introduced by the declaration can only occur as part of the declaration or in a constructor in the same class.
Example
In this example, the value of the field year cannot be changed in the method ChangeYear, even though it is assigned a value in the class constructor..."

As last time, I wrote unit tests to see if it is possible. 
commit to my github

Unfortunately Microsoft... Using reflection above sentence isn't true.

I added new class named "InternalCallReadonlyVsConst" and it looks like below

namespace InternalClasses
{
  class InternalCallReadonlyVsConst
  {
    private readonly int privateReadonlyInt = 100;
    private readonly string privateReadonlyString = "100";

    private static readonly int privateStaticReadonlyInt = 100;
    private static readonly string privateStaticReadonlyString = "100";
  }
}

I wrote tests checking the possiblity to change value of readonly and static readonly fields.
Answer is yes, both of them you can change the value.
I was thinking about how to protect yourself, so I added const fields as below.

namespace InternalClasses
{
  class InternalCallReadonlyVsConst
  {
    private readonly int privateReadonlyInt = 100;
    private readonly string privateReadonlyString = "100";

    private static readonly int privateStaticReadonlyInt = 100;
    private static readonly string privateStaticReadonlyString = "100";

    private const int privateConstInt = 100;
    private const string privateConstString = "100";
  }
}

When I try change the value of const fields I got "FieldAccessException" as you can see in my code. 

    [TestMethod()]
    public void CreateInternalClassInstanceAndSetConstFields()
    {
      object InternalCallReadonlyVsConst = ReflectionHelper.CreateInstanceOfInternalClass(
                      "InternalClasses", "InternalClasses", "InternalCallReadonlyVsConst");
      Assert.IsNotNull(InternalCallReadonlyVsConst);

      object privateConstInt = ReflectionHelper.GetNonPublicIntFiledValue(InternalCallReadonlyVsConst, 
                                            "privateConstInt", InternalCallReadonlyVsConst.GetType());
      Assert.IsNotNull(privateConstInt);
      Assert.IsTrue(privateConstInt is Int32);
      Assert.AreEqual(privateConstInt, 100);

      Assert.ThrowsException< FieldAccessException>(()=> privateConstInt = 
                ReflectionHelper.GetAndSetValue(InternalCallReadonlyVsConst, 1234, "privateConstInt"));
      Assert.IsNotNull(privateConstInt);
      Assert.IsTrue(privateConstInt is Int32);
      Assert.AreEqual(privateConstInt, 100);


      object privateConstString = ReflectionHelper.GetNonPublicIntFiledValue(InternalCallReadonlyVsConst, 
                                            "privateConstString", InternalCallReadonlyVsConst.GetType());
      Assert.IsNotNull(privateConstString);
      Assert.IsTrue(privateConstString is string);
      Assert.AreEqual(privateConstString, "100");

      Assert.ThrowsException(() => privateConstString = 
             ReflectionHelper.GetAndSetValue(InternalCallReadonlyVsConst, "1234", "privateConstString"));
      Assert.IsNotNull(privateConstString);
      Assert.IsTrue(privateConstString is string);
      Assert.AreEqual(privateConstString, "100");
    }

You can draw the conclusion. If security of your application important to you use const fields when it is possible.

In the next part I will show more examples of how to defend against reflection.

Komentarze

Popularne posty z tego bloga

Czarna lista produktów zawierających utwardzony tłuszcz roślinny. Aktualizacja 03.08.2013

[Part 1] Is c# safe? Are Internal class accessible only from the same assembly?

Olej palmowy w produktach