|Important||This document may not represent best practices for current development, links to downloads and other resources may no longer be valid. Current recommended version can be found here.|
Using the Deny Method
Calling Deny prevents access to the resource specified by the denied permission. If your code calls Deny and a downstream caller subsequently demands the denied permission, the security check will fail, even if all callers have permission to access that resource. The permission being demanded and the permission being denied do not have to match exactly for the Deny to take effect, and the demanded permission does not have to be a subset of the denied permission. However, if the intersection of the two permissions is empty (that is, if they have nothing in common), the call to Deny will have no effect. Note that Deny cannot override deeper code on the call stack that performs an Assert. If deeper code on the call stack performs an Assert, the deeper code can access the resource that code higher on the call stack denies.
You can use calls to Deny in your code to protect yourself from liability because Deny makes it impossible for your code to be used to access the denied resource. However, the call to Deny does not block future security assertions by downstream callers.
The following illustration shows what happens when you use Deny. Assume the following statements are true about assemblies A, B, C, D, and E, and permission P1:
P1 represents the right to read all files on the C drive.
Assemblies A, B, C, D, and E have been granted P1.
Method F places a demand on Permission P1.
Method C creates an instance of the P1 class and then calls P1's Deny method.
Method A is contained in assembly A, method B is contained in assembly B, and so on.
Method C's call to Deny can affect the outcome of demands for P1. For example, suppose that method A calls B, B calls C, C calls E, and E calls F. Because method F directly accesses the resource that P1 protects, method F invokes a security check for P1 by calling P1's Demand method (or by using a declarative demand). This demand causes the runtime to check the permissions of all callers in the call stack, starting with assembly E. Because assembly E has been granted P1 permission, the runtime proceeds to examine the permissions of assembly C. But because method C has denied P1, the security check invoked by method E fails at that point, and a SecurityException is thrown. It does not matter whether assembly C and its callers (assemblies A and B) have been granted P1; the security check still fails. Because method C called Deny, code in assemblies A and B cannot access the resource protected by P1.
The following code shows declarative syntax for overriding security checks using the Deny method. In this example, the ReflectionPermission syntax specifies two values: a SecurityAction enumeration and the setting for the TypeInformation property. TypeInformation is set to true to specify that this permission represents the right to view private members through reflection and SecurityAction.Deny is passed to deny that permission. See the description of ReflectionPermission for a complete list of values you can specify. With this security declaration, the method cannot read private members of a type through reflection.
Option Strict Option Explicit Imports System Imports System.Security.Permissions <ReflectionPermissionAttribute(SecurityAction.Deny, TypeInformation = true ")> Public Class MyClass1 Public Sub New() End Sub Public Sub GetPublicMembers () ' Access public members through reflection. End Sub End Class
The following code shows imperative syntax for overriding security checks using the Deny method. In this example, the ReflectionPermission object is declared and its constructor is passed ReflectionPermissionFlag.TypeInformation to initialize the current permission. When the Deny method is called, the code and callers can never be used to read private fields through reflection.
Option Explicit Option Strict Imports System Imports System.Security.Permissions Public Class MyClass1 Public Sub New() End Sub Public Sub ReadRegistry() Dim MyPermission As New ReflectionPermission (ReflectionPermissionFlag.TypeInformation) MyPermission.Deny() ' Access public members through reflection. End Sub End Class
Canonicalization Problems Using Deny
You should be extremely careful when denying FileIOPermission, RegistryPermission, WebPermission, UrlIdentityPermission, SiteIdentityPermission, and EnvironmentPermission because single files, registry entries, URLs, and system paths can be described using multiple names. For example, a single file, MyFile.log, can be referenced a number of ways, including "c:\MyFile.log" and "\\MyMachineName\c$\MyFile.log". If you create a permission that represents access to "c:\MyFile.log" and then deny that permission to your code, your code might still be able to access the file using the alternate path "\\MyMachineName\c$\MyFile.log".
You can use a combination of PermitOnly and Deny to avoid canonization problems. PermitOnly gives you the ability to specify only one of several possible names for a resource and has the side effect of denying access to that resource using any other name. After you use PermitOnly to specify the one allowed name for a resource, you should use Deny to disallow access to the resource using that name.
The following code uses a combination of Deny and PermitOnly to prevent your code from accessing a resource called MyLog.log. This code also blocks access to the resource using all alternative names or paths.