88

I recently came across a problem that I was having using C#, and it was solved by setting a private member using reflection.

I was stunned to find out that setting a private member/field and also running a private method are things that are allowed and possible in C#. This is not a question of how to do these things, they are well documented, my question is: why?

If you set a field/member/method as private/internal, why would C# as a language allow these fields to be set outside the scope? I would think that this would throw an exception of some kind. If the class wanted them to be changed or set wouldn't there be a method or a constructor?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Ryan Drost
  • 1,184
  • 10
  • 19
  • 95
    Once you are using Reflection, hand-emitting bytecode, etc you're saying 'Stuff the normal object oriented model, I need to do this and I need it now'. This means normal restrictions are lifted, since you are making your intent clear that you want to go around them. With great power comes great responsibility. – Patashu Jun 05 '13 at 14:09
  • 9
    See: [Security Considerations for Reflection](http://msdn.microsoft.com/en-us/library/stfy7tfc.aspx) – Ani Jun 05 '13 at 14:12
  • @MichaelKjörling eight now. – Geeky Guy Jun 05 '13 at 14:12
  • @Renan Or nine. This is turning parabolic. I'm outta here. ;) – user Jun 05 '13 at 14:13
  • A question like this has already been asked on SO, the only difference was that the language the OP of that question used was Java instead of C#. But those to are similar enough to use answers on this kind of question for both of them. – 11684 Jun 05 '13 at 14:33
  • 13
    Just to be pedantic, C# the language, doesn't allow this. The classes in the System.Reflection namespace are not C# specific. – Chris Dunaway Jun 05 '13 at 15:31
  • 37
    Debuggers would not be very useful if they couldn't access private members of the class you are debugging. – Raymond Chen Jun 05 '13 at 15:45
  • @11684 You should link to that question in your comment. Then the two threads will be "connected". – Jeppe Stig Nielsen Jun 05 '13 at 16:00
  • 5
    As an aside, consider the delights of this little snippet: typeof(String).GetField("Empty", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.GetField).SetValue(null, "foo" ); – Quibblesome Jun 05 '13 at 16:50
  • @Quibblesome For some reason, that does appear to not actually work. Would have been a great practical joke otherwise! – Eyvind Jun 06 '13 at 07:25
  • Doesn't anyone find it a bit strange that Silverlight DOES prevent access to private fields and methods even when using Reflection? And I think Silverlight still qualifies as C# and .NET, no? – MBender Jun 06 '13 at 08:34
  • @Eyvind, I'm pretty sure it used to. I either messed up the code or they patched it. – Quibblesome Jun 06 '13 at 12:24
  • @Quibblesome Well, the curious thing is that the debugger shows the value of String.Empty to be "foo" (i.e. if you hover over it with the mouse), but actual code still treats it as "". – Eyvind Jun 06 '13 at 13:56
  • 1
    @Shaamaan I guess you never have full trust when running in a browser. – Eyvind Jun 06 '13 at 13:57
  • 1
    Assumption: Reflection does not work on the language (c#), but on the runtime (MSIL) and therefore restrictions enforced by the compiler do not apply... – Daren Thomas Jun 05 '13 at 14:09
  • 1
    That's not it. At runtime, access modifiers are normally checked too. Just try it: create a program and a library, have the program use something from the library, change the access to private in the library, and run the program without recompiling. You'll get a runtime exception. –  Jun 05 '13 at 14:11
  • @hvd, I have to agree with you on that one... – Daren Thomas Jun 05 '13 at 14:16
  • I don't know why this question has proved so popular, but thanks for asking it :-) – Damien_The_Unbeliever Jun 07 '13 at 12:10
  • If it's security you're after, search Google for ".NET Code Access Security" – Razor Jun 12 '13 at 02:51
  • @VincePanuccio: Microsoft is dropping CAS: http://www.infoq.com/news/2009/11/CAS-Replaced –  Jun 16 '13 at 15:20
  • @Amy They are not dropping support, it's still there, you just need to enable it. It says so in the link you posted. – Razor Jun 18 '13 at 02:45

9 Answers9

132

Because the access modifiers are there to assist with documenting the API that you want to expose to consumers, or to inheritors, etc.

They're not a security/access control mechanism.

Damien_The_Unbeliever
  • 234,701
  • 27
  • 340
  • 448
  • 3
    I think that the existence of the keyword `unsafe` means that even if Reflection did not exist you could access private fields of a C# datatype. (I'm not game to try) – Patashu Jun 05 '13 at 14:12
  • 8
    @Patashu And even if that didn't exist, you could still call out to, for example, C++ code that can go around twiddling bits anywhere in the process's memory willy nilly. At the end of the day you can't stop a program from manipulating it's own memory space; in order to be able to function at all it needs to have enough access to do pretty much anything it wants with that memory. – Servy Jun 05 '13 at 14:22
  • 6
    I don't think it is completely fair to say access modifiers are not a security access control mechanism, though they don't provide security of the type discussed by the OP. See [Do the access levels and modifiers (private, sealed, etc) serve a security purpose in C#?](http://stackoverflow.com/q/891018/18192) . Per Eric Lippert: "Access restrictions mitigate attacks on your users by partially trusted hostile code." – Brian Jun 05 '13 at 17:00
63

It's impossible to prevent someone from being able to do that. You could make it harder, you could force them to use unsafe code and start setting bits around blindly. After all, it's their program/machine, they're allowed to do such things.

The design of the language is such that it makes it hard for you to shoot yourself in the foot and do Bad Things. But it doesn't make them impossible, doing so would also restrict users from doing things that are unusual, but still desirable.

Servy
  • 202,030
  • 26
  • 332
  • 449
  • 11
    This is my favorite answer. Modifying values is simply a mechanism of accessing memory -hence the massive *virus prevention/removal* market. The idea is that if you make something less visible to consumers they realize that *generally speaking* that's how the interface **should be used.** It also means that modifying data via `Reflection` could cause instabilities *(though I've done it)* :D – Mike Perrenoud Jun 05 '13 at 14:12
  • 2
    It's not impossible. Just really hard. For example, you can run a program so that every memory access is intercepted (using the mmu) and verified by either a separate process (using debugging APIs) or through the Kernel or a vm monitor of some sort. Such monitoring programs can introspect the memory access and make very complex policy decisions. It would be super slow, but it is possible. – Scott Wisniewski Jun 05 '13 at 22:46
  • @ScottWisniewski though what if someone were to also tamper with the memory of the software enforcing the access policy so it gives them access to modify the other process? :p – grinch Feb 06 '14 at 13:19
56

Private reflection requires that you be granted essentially full trust. Full trust means full trust. If you're fully trusted to be doing the right thing then why shouldn't that work?

(In fact, the security model for private reflection is actually much more complicated than I've sketched it here, but that does not affect my point: that this ability is subject to policy. See Security Considerations for Reflection (MSDN) for an overview of how reflection and security policy interact.)

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • 1
    Now this is the most clarity I've seen on private reflection ever. It requires *full trust*, thanks Eric! – Mike Perrenoud Jun 05 '13 at 14:23
  • @Michael it is actually quite a bit more complicated in practice. I am oversimplifying to make the point clear; this capability is controlled by a policy. – Eric Lippert Jun 05 '13 at 14:39
  • 1
    that little nugget in your comment though `controlled by a policy` is huge too -that makes perfect sense -and though I don't fully understand it yet it lets me know that network administrators could likely control that policy too so I shouldn't assume I'll always have access to private reflection. Again, gotta do some reading, but that was a great nugget. Thanks a lot! – Mike Perrenoud Jun 05 '13 at 14:41
14

Visibility modifiers aren't meant for security.

They are simply meant to make working with structured API's/codebases more effective - as to not bog the programmer down with guff - and only expose the things that consumers should be concerned with.

Dave Bish
  • 19,263
  • 7
  • 46
  • 63
6

Reflection is how you interact with compiled code. If reflection respected the source language's expectations about privacy, there would be a need for another mechanism just like it which didn't. Turtles all the way down.

Start by assuming that what it does is what it's meant to, then re-evaluate your assumption that it was a misguided effort to do something different that nobody wants to do anyway.

5

Sometimes, you have to cheat.

It's easy to say that the class should have a setter for something if it needs to be set, but what if you can't add one? What if it's not your class, it's a proprietary library and you need to work around a bug in it? I'm not saying that you should do such things, in fact I would say that you almost certainly shouldn't, but sometimes the only way to get something to work is outrageous cheating. In those cases, the fact that these mechanisms exist is extremely helpful.

You should, however, always question their use, and of course be aware that violating the public API of an object is likely to cause you problems further down the line and is probably the wrong thing to do. Except in the aforementioned scenario when it's the only way you can make something work in some code that you don't have the ability to change.

One thing to note is that C++ and its derivatives have strong access control, but there are a lot of OOP languages that don't. Perl 5 objects, for example, are entirely open to outside interference, and private methods and data are only there by convention - a Perl programmer knows that messing about inside a third-party object's hashref is probably going to break things, so they generally won't do that. Again as with C#'s reflection capabilities though, sometimes you can solve an awful lot of problems with a little tweak to something you're not really supposed to touch.

But I reiterate yet another time, you almost certainly shouldn't do it. These capabilities are not intended for everyday use.

Matthew Walton
  • 9,809
  • 3
  • 27
  • 36
5

I cannot even see my face without through something reflective. Okay, I can watch myself in a video, but that is done by the optical device called a camera, and it's also something use the technique of reflection.

If I were sick, I possibly would already be dead when doctors need X-rays to diagnose and treat my illness, but all kinds of reflections are unable to see what is private of me. And I can never see myself neither.

The X-ray (or something tomography-like) can watch the inside of me, what I can never do without it.

1kUml.jpg

I'd rather say it's more realistic than reflection. But yes, I cannot use my eyes to see the real me directly, every me that I've ever seen, were some kind of reflection. (To think it in depth, eyes also give us the reflection of reality.)

So, reflection is supposed to related to realistic, without a particular view. And you can assume that the consumers code is restricted to BindingFlags.Public, within the rules of object-orientation.

In the real universe, almost nothing is impossible; the only difference between possible and impossible to us, is whether it can done by human, since we are human beings.

It seems dangerous that reflection can do everything in the universe of programs, and now it's required to be fully trusted for the security reason, in a human's logic.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Ken Kin
  • 4,503
  • 3
  • 38
  • 76
3

Good question.

My answer would be: Access modifiers and visibility are part of the API design. With reflection, you have full control over pretty much everything, including bypassing the API and modifying data on the low level.

Access modifiers can make your classes safe from accidental changes from the outside. You can call a method or access a public member "by accident". With reflection, it is hard to maintain that you did things by accident.

And if this low level access on reflection were NOT possible, a lot of stuff that we all have come to know and like would be virtually impossible.

Jan Dörrenhaus
  • 6,581
  • 2
  • 34
  • 45
0

A case in production code:

We wanted one web service to work in the NZ timezone. Probably the correct solution is to rewrite all our code (including some .NET Framework serialization code) to use DateTimeOffset, but the simplest solution was effectively to adjust the two private fields in the .NET Framework that store the current timezone (normally based upon registry calls) to use the NZ timezone explicitly.

We know that if the .NET Framework version 2.0 is ever updated in its handling of time zones we may have to rework our code, but for the moment this is working fine in production.

Mark Hurd
  • 10,665
  • 10
  • 68
  • 101