Review deny and permit only usage

TypeName

ReviewDenyAndPermitOnlyUsage

CheckId

CA2107

Category

Microsoft.Security

Breaking Change

Breaking

Cause

A method contains a security check that specifies the PermitOnly or Deny security action.

Rule Description

The Using the PermitOnly Method and System.Security.CodeAccessPermission.Deny security actions should be used only by those with an advanced knowledge of .NET Framework security. Code that uses these security actions should undergo a security review.

Deny alters the default behavior of the stack walk that occurs in response to a security demand; it provides a way to specify permissions that must not be granted for the duration of the denying method, regardless of the actual permissions of the callers in the call stack. If the stack walk detects a method secured by Deny, and if the demanded permission is included in the denied permissions, the stack walk fails. PermitOnly also alters the default behavior of the stack walk; it allows code to specify only those permissions that can be granted, regardless of the callers' permissions. If the stack walk detects a method secured by PermitOnly, and if the demanded permission is not included in the permissions specified by the PermitOnly, the stack walk fails.

Code that relies on these actions should be carefully evaluated for security vulnerabilities because of their limited usefulness and subtle behavior. Consider the following:

  • Link Demands are not affected by Deny or PermitOnly.

  • If the Deny or PermitOnly occurs in the same stack frame as the demand that causes the stack walk, the security actions have no effect.

  • Values used to construct path-based permissions can usually be specified in multiple ways. Denying access to one form of the path does not deny access to all forms. For example, if a file share \\Server\Share is mapped to a network drive X:, to deny access to a file on the share, you must deny \\Server\Share\File, X:\File, and every other path that accesses the file.

  • An System.Security.CodeAccessPermission.Assert can terminate a stack walk before the Deny or PermitOnly is reached.

  • If a Deny has any effect, namely, when a caller has a permission blocked by the Deny, then the caller can access the protected resource directly, bypassing the Deny. Similarly, if the caller does not have the denied permission, the stack walk would fail without the Deny.

How to Fix Violations

Any use of these security actions will cause a violation. To fix a violation, do not use these security actions.

When to Exclude Warnings

Exclude a warning from this rule only after you complete a security review.

Example

The following example demonstrates some limitations of Deny.

The following library contains a class with two methods that are identical except for the security demands protecting them.

using System.Security;
using System.Security.Permissions;
using System;

namespace SecurityRulesLibrary
{
   public  class SomeSecuredMethods
   {
    
      // Demand immediate caller has suitable permission
      // before revealing sensitive data.
      [EnvironmentPermissionAttribute(SecurityAction.LinkDemand,
          Read="COMPUTERNAME;USERNAME;USERDOMAIN")]

      public static void MethodProtectedByLinkDemand()
      {
         Console.Write("LinkDemand: ");
      }

      [EnvironmentPermissionAttribute(SecurityAction.Demand,
          Read="COMPUTERNAME;USERNAME;USERDOMAIN")]

      public static void MethodProtectedByDemand()
      {
         Console.Write("Demand: ");
      }
   }
}

The following application demonstrates the effects of Deny on the secured methods from the library.

using System.Security;
using System.Security.Permissions;
using System;
using SecurityRulesLibrary;

namespace TestSecurityLibrary
{
    // Violates rule: ReviewDenyAndPermitOnlyUsage.
   public class TestPermitAndDeny
   {
      public static void TestAssertAndDeny()
      {
         EnvironmentPermission envPermission = new EnvironmentPermission(
               EnvironmentPermissionAccess.Read,
               "COMPUTERNAME;USERNAME;USERDOMAIN");
         envPermission.Assert();
         try
         {
            SomeSecuredMethods.MethodProtectedByDemand();
            Console.WriteLine(
               "Caller's Deny has no effect on Demand " + 
               "with the asserted permission.");

            SomeSecuredMethods.MethodProtectedByLinkDemand();
            Console.WriteLine(
               "Caller's Deny has no effect on LinkDemand " + 
               "with the asserted permission.");
         }
         catch (SecurityException e)
         {
            Console.WriteLine(
               "Caller's Deny protected the library.{0}", e);
         }
      }

      public static void TestDenyAndLinkDemand()
      {
         try
         {
            SomeSecuredMethods.MethodProtectedByLinkDemand();
            Console.WriteLine(
               "Caller's Deny has no effect with " +
               "LinkDemand-protected code.");
         }
         catch (SecurityException e)
         {
            Console.WriteLine(
               "Caller's Deny protected the library.{0}",e);
         }
      }
         
      public static void Main()
      {
         EnvironmentPermission envPermission = new EnvironmentPermission(
            EnvironmentPermissionAccess.Read,
            "COMPUTERNAME;USERNAME;USERDOMAIN");
         envPermission.Deny();

         //Test Deny and Assert interaction for LinkDemands and Demands.
         TestAssertAndDeny();

         //Test Deny's effects on code in different stack frame. 
         TestDenyAndLinkDemand();

         //Test Deny's effect on code in same frame as deny.
         try
         {
            SomeSecuredMethods.MethodProtectedByLinkDemand();
            Console.WriteLine(
               "This Deny has no effect with LinkDemand-protected code.");
         }
         catch (SecurityException e)
         {
            Console.WriteLine("This Deny protected the library.{0}",e);
         }
      }
   }
}

This example produces the following output.

Output

Demand: Caller's Deny has no effect on Demand with the asserted permission.
LinkDemand: Caller's Deny has no effect on LinkDemand with the asserted permission.
LinkDemand: Caller's Deny has no effect with LinkDemand-protected code.
LinkDemand: This Deny has no effect with LinkDemand-protected code.

See Also

Reference

System.Security.CodeAccessPermission.PermitOnly
System.Security.CodeAccessPermission.Assert
System.Security.CodeAccessPermission.Deny
System.Security.IStackWalk.PermitOnly

Concepts

Overriding Security Checks
Using the PermitOnly Method

Other Resources

Secure Coding Guidelines