Recipe17.9.Making a Security Assert Safe


Recipe 17.9. Making a Security Assert Safe

Problem

You want to assert that at a particular point in the call stack, a given permission is available for all subsequent calls. However, doing this can easily open a security hole to allow other malicious code to spoof your code or to create a back door into your component. You want to assert a given security permission, but you want to do so in a secure and efficient manner.

Solution

In order to make this approach secure, you need to call Demand on the permissions that the subsequent calls need. This makes sure that code that doesn't have these permissions can't slip by due to the Assert. The Demand is done to ensure that you have indeed been granted this permission before using the Assert to short-circuit the stackwalk. This is demonstrated by the function CallSecureFunctionSafelyAndEfficiently, which performs a Demand and an Assert before calling SecureFunction, which in turn does a Demand for a ReflectionPermission.

The code listing for CallSecureFunctionSafelyAndEfficiently is shown in Example 17-14.

Example 17-14. CallSecureFunctionSafelyAndEfficiently function

 public static void CallSecureFunctionSafelyAndEfficiently( ) {     // Set up a permission to be able to access nonpublic members     // via reflection.     ReflectionPermission perm =         new ReflectionPermission(ReflectionPermissionFlag.MemberAccess);     // Demand the permission set we have compiled before using Assert     // to make sure we have the right before we Assert it. We do     // the Demand to ensure that we have checked for this permission     // before using Assert to short-circuit stackwalking for it, which     // helps us stay secure, while performing better.     perm.Demand( );     // Assert this right before calling into the function that     // would also perform the Demand to short-circuit the stack walk     // each call would generate. The Assert helps us to optimize     // our use of SecureFunction.     perm.Assert( );     // We call the secure function 100 times but only generate     // the stackwalk from the function to this calling function     // instead of walking the whole stack 100 times.     for(int i=0;i<100;i++)     {         SecureFunction( );     } } 

The code listing for SecureFunction is shown here:

 public static void SecureFunction( ) {     // Set up a permission to be able to access nonpublic members     // via reflection.     ReflectionPermission perm =         new ReflectionPermission(ReflectionPermissionFlag.MemberAccess);     // Demand the right to do this and cause a stackwalk.     perm.Demand( );     // Perform the action here… } 

Discussion

In the demonstration function CallSecureFunctionSafelyAndEfficiently, the function you are calling (SecureFunction) performs a Demand on a ReflectionPermission to ensure that the code can access nonpublic members of classes via reflection. Normally, this would result in a stackwalk for every call to SecureFunction. The Demand in CallSecureFunctionSafelyAndEfficiently is there only to protect against the usage of the Assert in the first place. To make this more efficient, you can use Assert to state that all functions issuing Demands that are called from this one do not have to stackwalk any further. The Assert says stop checking for this permission in the call stack. In order to do this, you need the permission to call Assert.

The problem comes in with this Assert as it opens up a potential luring attack where SecureFunction is called via CallSecureFunctionSafelyAndEfficiently, which calls Assert to stop the Demand stackwalks from SecureFunction. If unauthorized code without this ReflectionPermission were able to call CallSecureFunctionSafelyAndEfficiently, the Assert would prevent the SecureFunction Demand call from determining that there is some code in the call stack without the proper rights. This is the power of the call stack checking in the CLR when a Demand occurs.

In order to protect against this, you issue a Demand for the ReflectionPermission needed by SecureFunction in CallSecureFunctionSafelyAndEfficiently to close this hole before issuing the Assert. The combination of this Demand and the Assert causes

you to do one stack walk instead of the original 100 that would have been caused by the Demand in SecureFunction but to still maintain secure access to this functionality.

Security optimization techniques, such as using Assert in this case (even though it isn't the primary reason to use Assert), can help class library as well as control developers who are trusted to perform Asserts in order to speed the interaction of their code with the CLR; but if used improperly, these techniques can also open up holes in the security picture. This example shows that you can have both performance and security where secure access is concerned.

If you are using Assert, be mindful that stackwalk overrides should never be made in a class constructor. Constructors are not guaranteed to have any particular security context, nor are they guaranteed to execute at a specific point in time. This lack leads to the call stack not being well defined, and Assert used here can produce unexpected results.

One other thing to remember with Assert is that you can have only one active Assert in a function at a given time. If you Assert the same permission twice, a SecurityException is thrown by the CLR. You must revert the original Assert first using RevertAssert. Then you can declare the second Assert.

See Also

See the "CodeAccessSecurity.Assert Method," "CodeAccessSecurity.Demand Method," "CodeAccessSecurity.RevertAssert Method," and "Overriding Security Checks" topics in the MSDN documentation.



C# Cookbook
Secure Programming Cookbook for C and C++: Recipes for Cryptography, Authentication, Input Validation & More
ISBN: 0596003943
EAN: 2147483647
Year: 2004
Pages: 424

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net