Assert is a stack walk modifier. It doesn't modify the permission grant that any assembly has, rather it prevents the stack walk for a permission demand from continuing up the call stack. Assert is effective because it stops a permission demand from ever reaching assemblies without the given permission.
Assert should never be used as a perf optimization. Oftentimes, in an attempt to speed up the security system, people think of using Assert to stop the call stack walk. Doing this completely circumvents the CAS system, and will more than likely lead to a security hole down the line. It's very unlikely that if your application is having performance problems that stopping a security stack walk early on will solve them, you should instead measure and measure again, then fix the areas that are actually causing the problem.
This one is pretty easy to get confused about because of the observed behavior. When you Assert some permissions, the code doing the Assert needs to be granted the following two things:
- SecurityPermission with SecurityPermissionFlag.Assertion set. If this is not true, calling Assert will result in a SecurityException.
- The permissions being asserted. If this is not true, there's no observable runtime behavior difference (causing the confusion that leads to this myth). The call to Assert will return as if the assertion were set, however when a subsequent demand occurs, the Assert will not stop the stack walk.
Since Assert is a stack walk modifier, it is only in effect while the method that called Assert is still on the call stack. Once this method returns and its frame is popped, the Assert is no longer in effect.
While this is technically not a myth, and is true, good coding practice is to always Assert immediately before calling whatever method will result in the permission demand, and call RevertAssert as soon as you don't need the elevated permissions any more. This limits the window of time that malicious code could use to take advantage of the stack walk modifier.
This is probably the most common misconception I see about Assert. Asserting a set of permissions will only prevent a stack walk for those permissions from going further up the call stack. For instance, if I assert FileIOPermission, and code I call demands RegistryPermission, that stack walk will blow right by my Assert and head further up the call stack.
A more interesting scenario occurs when a demand occurs that is a superset of the set of permissions that I've Asserted. For instance, if I Assert FileIOPermission, but some code I call demands a permission set containing both FileIO and Registry permission. Clearly stopping at my Assert would be the wrong behavior, but so would continuing past it. In this case, when the CLR hits the Assert it will remove any permissions being Asserted from the permission set being demanded, and send the remaining permissions further on the stack walk.
I've already covered three cases where an Assert will not prevent a SecurityException (Myths #3, 4, and 6). There are at least two other ways that this can happen. Can you figure them out? Post your guesses in the comments, and I'll provide answers in tomorrow's post.