Export (0) Print
Expand All

Key Security Concepts

The Microsoft .NET Framework offers security transparency, code access security and role-based security to help address security concerns about mobile code and to provide support that enables components to determine what users are authorized to do. These security mechanisms use a simple, consistent model so that developers familiar with code access security can easily use role-based security, and vice versa. Both code access security and role-based security are implemented using a common infrastructure supplied by the common language runtime.

Note Note

Starting with the .NET Framework 4, security transparency is the default enforcement mechanism. Security transparency separates code that runs as part of the application from code that runs as part of the infrastructure. For more information, see Security-Transparent Code.

Because they use the same model and infrastructure, code access security and role-based security share several underlying concepts, which are described in this section. Make sure that you are familiar with these concepts before reading the documentation for .NET Framework code access security and role-based security.

The common language runtime allows code to perform only those operations that the code has permission to perform. The runtime uses objects called permissions to enforce restrictions on managed code. The runtime provides built-in permission classes in several namespaces and also supports designing and implementing custom permission classes.

There are two kinds of permissions, and each has a specific purpose:

  • Code Access Permissions represent access to a protected resource or the ability to perform a protected operation.

  • Role-Based Security Permissions provide a mechanism for discovering whether a user (or the agent acting on the user's behalf) has a particular identity or is a member of a specified role. PrincipalPermission is the only role-based security permission.

Security permissions can be in the form of a permission class (imperative security) or an attribute that represents a permission class (declarative security). The base class for security permissions is System.Security.CodeAccessPermission; the base class for security permission attributes is System.Security.Permissions.CodeAccessSecurityAttribute.

An application, in the form of an assembly, is granted a set of permissions at the time it is loaded into an application domain. The grants are typically made by using predefined permission sets that are determined by the SecurityManager.GetStandardSandbox method. The grant set determines the permissions the code has available to it. The runtime grants permissions based on the code's origin location (for example, the local machine, local intranet, or the Internet). Code can also be granted special permissions if it is loaded into a sandbox. For more information about running code in a sandbox, see How to: Run Partially Trusted Code in a Sandbox.

The primary uses of permissions are as follows:

  • Library code can demand that its callers have specific permissions. If you place a Demand for a permission in your code, all code that uses your code is expected to have that permission to run. Demands can be used to determine whether callers have access to specific resources or to discover the identity of a caller.

  • Code can use permissions to deny access to resources it wants to protect. You can use SecurityAction.PermitOnly to specify a limited permission set, implicitly denying all other permissions. However, we do not recommend using PermitOnly to prohibit access for the purpose of protecting against intentional misuse. Called assemblies, which have the implicitly refused permissions in their grant set, can override denied permissions by performing an SecurityAction.Assert for any permission they want to use. For example, if you permitted only UIPermission and called an assembly that inherently has FileIOPermission, the assembly can simply do an Assert for FileIOPermission and perform file operations. The only way to securely protect resources from untrusted code in referenced assemblies is to execute that code with a grant set that does not include those permissions.

Code access permissions are permission objects that are used to help protect resources and operations from unauthorized use. They are a fundamental part of the common language runtime's mechanism for enforcing security restrictions on managed code.

Each code access permission represents one of the following rights:

  • The right to access a protected resource, such as files or environment variables.

  • The right to perform a protected operation, such as accessing unmanaged code.

All code access permissions can be requested or demanded by code, and the runtime decides which permissions, if any, to grant the code.

Each code access permission derives from the CodeAccessPermission class, which means that all code access permissions have methods in common, such as Demand, Assert, Deny, PermitOnly, IsSubsetOf, Intersect, and Union.

Important note Important

In the .NET Framework 4, runtime support has been removed for enforcing the Deny, RequestMinimum, RequestOptional, and RequestRefuse permission requests. These requests should not be used in code that is based on .NET Framework 4 or later. For more information about this and other changes, see Security Changes in the .NET Framework.

PrincipalPermission is a role-based security permission that can be used to determine whether a user has a specified identity or is a member of a specified role. PrincipalPermission is the only role-based security permission supplied by the .NET Framework class library.

Type-safe code accesses only the memory locations it is authorized to access. (For this discussion, type safety specifically refers to memory type safety and should not be confused with type safety in a broader respect.) For example, type-safe code cannot read values from another object's private fields. It accesses types only in well-defined, allowable ways.

During just-in-time (JIT) compilation, an optional verification process examines the metadata and Microsoft intermediate language (MSIL) of a method to be JIT-compiled into native machine code to verify that they are type safe. This process is skipped if the code has permission to bypass verification. For more information about verification, see Managed Execution Process.

Although verification of type safety is not mandatory to run managed code, type safety plays a crucial role in assembly isolation and security enforcement. When code is type safe, the common language runtime can completely isolate assemblies from each other. This isolation helps ensure that assemblies cannot adversely affect each other and it increases application reliability. Type-safe components can execute safely in the same process even if they are trusted at different levels. When code is not type safe, unwanted side effects can occur. For example, the runtime cannot prevent managed code from calling into native (unmanaged) code and performing malicious operations. When code is type safe, the runtime's security enforcement mechanism ensures that it does not access native code unless it has permission to do so. All code that is not type safe must have been granted SecurityPermission with the passed enum member SkipVerification to run.

For more information, see Writing Verifiably Type-Safe Code.

A principal represents the identity and role of a user and acts on the user's behalf. Role-based security in the .NET Framework supports three kinds of principals:

  • Generic principals represent users and roles that exist independent of Windows users and roles.

  • Windows principals represent Windows users and their roles (or their Windows groups). A Windows principal can impersonate another user, which means that the principal can access a resource on a user's behalf while presenting the identity that belongs to that user.

  • Custom principals can be defined by an application in any way that is needed for that particular application. They can extend the basic notion of the principal's identity and roles.

For more information, see Principal and Identity Objects.

Authentication is the process of discovering and verifying the identity of a principal by examining the user's credentials and validating those credentials against some authority. The information obtained during authentication is directly usable by your code. You can also use .NET Framework role-based security to authenticate the current user and to determine whether to allow that principal to access your code. See the overloads of the WindowsPrincipal.IsInRole method for examples of how to authenticate the principal for specific roles. For example, you can use the WindowsPrincipal.IsInRole(String) overload to determine if the current user is a member of the Administrators group.

A variety of authentication mechanisms are used today, many of which can be used with .NET Framework role-based security. Some of the most commonly used mechanisms are basic, digest, Passport, operating system (such as NTLM or Kerberos), or application-defined mechanisms.

The following example requires that the active principal be an administrator. The name parameter is null, which allows any user who is an administrator to pass the demand.

Note Note

In Windows Vista, User Account Control (UAC) determines the privileges of a user. If you are a member of the Built-in Administrators group, you are assigned two run-time access tokens: a standard user access token and an administrator access token. By default, you are in the standard user role. To execute the code that requires you to be an administrator, you must first elevate your privileges from standard user to administrator. You can do this when you start an application by right-clicking the application icon and indicating that you want to run as an administrator.

using System;
using System.Threading;
using System.Security.Permissions;
using System.Security.Principal;

class SecurityPrincipalDemo
{

    public static void Main()
    {
        AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
        PrincipalPermission principalPerm = new PrincipalPermission(null, "Administrators");
        principalPerm.Demand();
        Console.WriteLine("Demand succeeded.");
    }
}

The following example demonstrates how to determine the identity of the principal and the roles available to the principal. An application of this example might be to confirm that the current user is in a role you allow for using your application.

using System;
using System.Threading;
using System.Security.Permissions;
using System.Security.Principal;

class SecurityPrincipalDemo
{
    public static void DemonstrateWindowsBuiltInRoleEnum()
    {
        AppDomain myDomain = Thread.GetDomain();

        myDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
        WindowsPrincipal myPrincipal = (WindowsPrincipal)Thread.CurrentPrincipal;
        Console.WriteLine("{0} belongs to: ", myPrincipal.Identity.Name.ToString());
        Array wbirFields = Enum.GetValues(typeof(WindowsBuiltInRole));
        foreach (object roleName in wbirFields)
        {
            try
            {
                // Cast the role name to a RID represented by the WindowsBuildInRole value.
                Console.WriteLine("{0}? {1}.", roleName,
                    myPrincipal.IsInRole((WindowsBuiltInRole)roleName));
                Console.WriteLine("The RID for this role is: " + ((int)roleName).ToString());

            }
            catch (Exception)
            {
                Console.WriteLine("{0}: Could not obtain role for this RID.",
                    roleName);
            }
        }
        // Get the role using the string value of the role.
        Console.WriteLine("{0}? {1}.", "Administrators",
            myPrincipal.IsInRole("BUILTIN\\" + "Administrators"));
        Console.WriteLine("{0}? {1}.", "Users",
            myPrincipal.IsInRole("BUILTIN\\" + "Users"));
        // Get the role using the WindowsBuiltInRole enumeration value.
        Console.WriteLine("{0}? {1}.", WindowsBuiltInRole.Administrator,
           myPrincipal.IsInRole(WindowsBuiltInRole.Administrator));
        // Get the role using the WellKnownSidType.
        SecurityIdentifier sid = new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null);
        Console.WriteLine("WellKnownSidType BuiltinAdministratorsSid  {0}? {1}.", sid.Value, myPrincipal.IsInRole(sid));
    }

    public static void Main()
    {
        DemonstrateWindowsBuiltInRoleEnum();
    }
}

Authorization is the process of determining whether a principal is allowed to perform a requested action. Authorization occurs after authentication and uses information about the principal's identity and roles to determine what resources the principal can access. You can use .NET Framework role-based security to implement authorization.

You should never base the security of your application on a member that is marked with the internal virtual modifier in C# (the Overloads Overridable Friend modifier in Visual Basic). Although members marked with these modifiers can only be overridden by other members within the current assembly, this rule is enforced only by the C# and Visual Basic languages. The runtime does not enforce this rule. It is therefore possible to override members marked as internal virtual in C# and Overloads Overridable Friend in Visual Basic using Microsoft Intermediate Language, or any other language that does not enforce this rule.

Show:
© 2015 Microsoft