Replace all child object permissions with inheritable permissions from this object access denied

Authorizing Users

Once you have verified a user's identity, you must determine whether that user has access to the requested resource. Authorizing a user is the process of verifying a user's rights to access a resource. Perhaps the greatest security improvements in ASP.NET are in the area of user authorization. In this section, we will cover:

Deciding how to authorize

Configuring file authorization

Implementing URL authorization

Authorizing through code

Deciding How to Authorize

Summary: In-depth authorization strategies are the basis for sound application security
Threats: Unauthorized access, privilege escalation

Classic ASP had no built-in authorization features—you either handled it entirely with custom code or let the underlying operating system handle it with little interaction from your ASP code. ASP.NET introduces a robust authorization infrastructure with so many new features and concepts that it is almost overwhelming to users who are new to ASP.NET.

Unfortunately, this robustness could be intimidating enough to cause some to avoid learning and implementing these features, but it is critical that you understand ASP.NET authorization to be able to build a solid security groundwork for your applications.

ASP.NET applications will work fine without any authorization, and some developers might not understand the need for authorization once the user has been authenticated. In fact, many ASP applications simply imply that users are authorized because they are authenticated. For example, Web sites commonly have an admin area for site maintenance and other privileged functions. To gain access to these functions, you provide an administrative username and password. The drawback is that this method either allows all access or denies all access. Authorization allows you to granularly define roles and the way those roles can interact with your application's operations or resources. Authentication concerns allowing access, but authorization precisely defines what access is allowed.

Identities, Principals, and Roles

Authentication is a key part of authorization. Before allowing or denying permissions to a user, you first must know the identity of that user. The .NET Framework represents users with identity and principal objects. A principal object corresponds to a user and contains an identity object that represents that user's details. Users can be categorized into different groups, or roles, such as administrators and users.

The principal object implements the IPrincipal interface that allows you to check role membership and provides an IIdentity object:

Replace all child object permissions with inheritable permissions from this object access denied

The Identity object implements the IIdentity interface and provides additional details of the user's identity:

Replace all child object permissions with inheritable permissions from this object access denied

The .NET Framework contains several objects that implement the IPrincipal and IIdentity interfaces. The objects you use depend on which method you use to authenticate users. Table 2.1 shows which objects to use for different authentication scenarios. Note that in addition to these built-in objects, you can also create and manage your own custom principal and identity objects.

Table 2.1. Authentication Types with Associated Principal and Identity Objects

Authentication MethodPrincipal ObjectIdentity ObjectCredentialsRoles
Forms GenericPrincipal FormsIdentity Stored in web.config or custom authentication code Established with custom code
Windows GenericPrincipal WindowsIdentity Provided by underlying operating system or domain Windows or Active Directory Groups
Passport GenericPrincipal PassportIdentity .NET Passport Established based on custom groups of Passport users

Roles and Resources

There are two basic approaches to user authorization in ASP.NET: role-based and resource-based. Role-based access control (RBAC) authorizes users based on membership in logical groups, or roles. Resource-based authorization, similar discretionary access control (DAC), works by granting or revoking access on individual resources based on individual users or groups. In many ways these two approaches are similar, but the primary difference is that resource-based authorization is specific to tangible resources and is specific to users and groups on the underlying operating system or network. Role-based authorization is more abstract and is independent of the operating system or its resources.

Therefore, resource-based authorization is similar to applying a discretionary access control list (DACL) granting BUILTIN\Users Read access to the c:\inetpub\wwwroot\members\ directory and its files. Role-based authorization is similar to granting members, through code or the web.config file, permission to access the Members application. Resource-based authorization depends on how Windows defines the BUILTIN\Users group and the physical location of the Members directory. Role-based authorization depends on the way the application defines the Members role and the Members application.

Because role-based authorization is more abstract and independent of the underlying infrastructure, it provides more flexibility and scalability than resource-based authorization. Even so, it is common to implement resource-based authorization as a means of implementing role-based authorization. The abstraction of role-based authorization also makes it a natural representation of an organization's structures, rules, and processes.

TIP

With role-based authorization, you can easily enable or disable application functions based on role membership. For example, you might want to provide an Advanced User role and provide enhanced user interface options for members of that role. Further, you could establish a Locked Down role for user accounts suspected of security breaches and disable certain account operations while users are members of that role.

In ASP.NET, there are several approaches to role-based authorization, which are described in more detail later in this chapter:

URL authorization

Declarative user-based security

Imperative user-based security

Explicit role checks

Security Policies

Implement strong authorization groundwork early in the application design.

Develop a solid role-based authorization scheme.

Use resource-based authorization to enhance role-based authorization.

Always use multiple layers of role-based and resource-based authorization.

Employing File Authorization

Summary: File authorization provides a layered and granular approach to security
Threats: Unauthorized access, privilege escalation

File authorization is the process of allowing access to file resources by setting appropriate access control lists (ACLs) to Web content files. There is nothing to configure in ASP.NET, and in fact every ASP.NET application automatically uses file authorization; you cannot turn it off. File authorization is not controlled by ASP.NET but is a function of the NTFS file system.

You may wonder, therefore, why ASP.NET even provides a file authorization module if it is already handled by the operating system. The reasons ASP.NET includes file authorization are:

Impersonation is not required for file authorization to work. The operating system therefore only sees the file request coming from the context of the ASP.NET process. ASP.NET handles the appropriate access checks for the requesting user.

ASP.NET may not access the file directly but instead accesses the compiled assembly for the file.

Because ASP.NET checks the NTFS permissions, it is able to handle and recover from any security exceptions due to failed access.

You configure file authorization by accessing the security properties of the file in Windows Explorer, using a tool such as xcacls.exe, through security templates, or through Group Policy. Because ASP.NET enforces file authorization based on file ACLs, it requires a valid Windows identity; therefore, it works only with Windows authentication. In fact, if no WindowsIdentity is associated with the request, it will not perform any access check at all. The same is true for any file types not mapped to ASP.NET. IIS and the underlying operating system will, however, still perform these checks. It is thus important that you understand the security context of the threads that will access files so that you can set appropriate permissions.

It is valuable to always use some form of file authorization, even if you don't have a complete understanding of ACLs and security contexts. At a minimum, you should allow users only read access to Web content. NTFS provides many granular settings; the more you take advantage of these settings, the more robust your application's security becomes.

TIP

Every object in Windows has three ACLs: one for itself, one to pass on to child objects (files), and one to pass on to child containers (directories). One technique for achieving extra-tight security is to set the inheritable permissions on a directory so that new child objects have little or no access. This forces you to explicitly set NTFS permissions for all new files and directories, but it also restricts access if an attacker is somehow able to create a new file or directory.

Although file authorization is resource-based access control, you can also take advantage of Windows or Active Directory groups to implement a role-based strategy.

Security Policies

Always set restricted NTFS permissions on Web content files, even if not using Windows authentication and file authorization.

Use file authorization to implement both resource-based and role-based security.

Apply specific and detailed NTFS permissions to increase application security.

Users should only be allowed read access to Web content.

Applying URL Authorization

URL authorization is a mechanism to control access based on the user, role, resource, or HTTP verb used. URL authorization is based on the principal associated with the request, so it works with any form of authentication. It also allows setting restrictions for unauthenticated users.

URL authorization is an effective means of enforcing least privilege to a Web application by precisely defining who can access what and how. You can configure URL authentication by editing the web.config for the application you want to protect. Each application's web.config will override the settings of any parent applications.

Users and Roles

The following section from a web.config file is an example of URL authorization:

Replace all child object permissions with inheritable permissions from this object access denied

Note that URL authorization uses the question mark (?) to indicate any unauthenticated users and the asterisk (*) to indicate all users. In this example, the code denies any unauthenticated users and allows those who have authenticated. The following examples are all valid formats for identifying users:

Replace all child object permissions with inheritable permissions from this object access denied

Roles are identified in a similar manner:

Replace all child object permissions with inheritable permissions from this object access denied

ASP.NET processes URL authorization settings from the top to the bottom, stopping with the first match it finds and ignoring any subsequent elements. Therefore, you should carefully consider the order of the elements. If you are configuring URL authorization for protected content, there are two basic techniques for controlling access. One technique is to begin by denying unauthenticated users, followed by denying specific users or roles, and ending by allowing all users. The following example demonstrates this method:

Replace all child object permissions with inheritable permissions from this object access denied

This example basically forces users to authenticate, denies expired users, and allows everyone else. In this example, it is crucial that you deny unauthenticated users with the first line. Otherwise, the configuration would look like this:

Replace all child object permissions with inheritable permissions from this object access denied

By not denying unauthenticated users, the system will begin by checking to see if the user is a member of the Expired role. Since the user is not yet authenticated, he or she is not a member of any role, and therefore this element will not match. The next element allows all users, which will match, and they will be allowed access to the application.

Another of the more popular techniques is to deny unauthenticated users, allow specific users or roles, and then deny everyone else:

Replace all child object permissions with inheritable permissions from this object access denied

This example forces all users to authenticate, allows those users who are Managers to access the application, but denies everyone else. With this method it is crucial that you include the last line that denies all users. If the user does not match any of the authorization elements, he or she is by default granted access, unless the web.config in a parent directory explicitly denies access.

HTTP Verbs

You can also use URL authentication to block certain HTTP verbs. For example, if you have a Web form and want to ensure that users always use the POST method, you can do this:

Replace all child object permissions with inheritable permissions from this object access denied

Note that in this example, we allow any requests from any users using the POST verb. In the next line we deny all requests from all users. We do this because any verb besides POST would not match the first line and therefore would be allowed. In other words, the allow element explicitly defines verbs that are allowed, but it does not define verbs that are not allowed. When specifying verbs with the allow element, you must always follow it with a deny element. The following example accomplishes the same as the previous one:

Replace all child object permissions with inheritable permissions from this object access denied

Note that not specifying the verbs attribute is equivalent to allowing or denying all verbs supported by ASP.NET (GET, HEAD, POST, and DEBUG).

WARNING

You might want to use URL authorization to block CGI vulnerability scanners that use the HTTP HEAD verb. Although you can block the scanner from sending HEAD requests to files that exist, it will still return a “404 Not Found” error message if the file doesn't exist. Therefore, the scanner simply needs to know that the status code 401 Unauthorized rather than the usual 200 OK means the file exists.

There are some limitations with using URL authorization to restrict HTTP verbs:

You cannot specify wildcards in the verbs attribute.

You easily specify different settings for different types of files (unless you use the location element described later).

A blocked verb returns a 401 Unauthorized status code rather than the more correct 405 Method Not Allowed status code. By returning a 401, if a request uses a denied verb, the user will be prompted to enter credentials, but even the correct credentials will return yet another 401 error.

The HttpMethodNotAllowedHandler gives you more control over blocking verbs. You can add this handler to your web.config file as shown here:

Replace all child object permissions with inheritable permissions from this object access denied

This example blocks all verbs to any file with the .mdb extension. Note that for this example to work, the file extension *.mdb must be explicitly mapped to the aspnet_isapi.dll or have a wildcard mapping in the application for aspnet_isapi.dll. The path attribute can contain wildcard characters in any part of the path as follows:

Replace all child object permissions with inheritable permissions from this object access denied

It is interesting to note that the verb attribute can also handle wildcard characters, unlike the verbs attribute that URL authentication uses. The HttpMethodNotAllowedHandler does not provide any authorization for particular users; it simply returns a “405 Method Not Allowed” error message for any requests that match the given verb and path. It is useful for flexible blocking of HTTP verbs but does not provide per-user settings. The best approach is to use a combination of the URL authorization verb attribute and HttpMethodNotAllowedHandler.

Files and Paths

You can also use URL authorization to set restrictions on individual files and paths using the location element, as shown here:

Replace all child object permissions with inheritable permissions from this object access denied

In this example, the first element leaves the path blank, which refers to the current directory and denies all unauthenticated users from accessing any files in that directory. The second location element defines the path to the default.aspx file and allows all users to access that file. This allows unauthenticated users to access a homepage but requires authentication before accessing any other files. It is interesting to note that the order of the location elements has no effect on how they are processed. This is because the default.aspx file is a child of the current application and therefore treats the configuration as a hierarchy. (Configuration hierarchies are explained in more detail later in this chapter.)

You can use location elements to completely block access to a specific file:

Replace all child object permissions with inheritable permissions from this object access denied

Note that you cannot use wildcards in the path settings, so you can set the location path to either the entire directory or to each individual file you want to have different authorization settings. If you want to completely block all users from accessing a file by wildcard, you can add the following to the web.config file:

Replace all child object permissions with inheritable permissions from this object access denied

For this example to work, the file extension *.mdb must be explicitly mapped to the aspnet_isapi.dll or have a wildcard mapping in the application for aspnet_isapi.dll. The path and verb attributes both support wildcards such as HttpMethodNotAllowedHandler already mentioned. See the section in the machine.config file for examples of how ASP.NET uses HttpForbiddenHandler to block certain file extensions.

TIP

In addition to HttpForbiddenHandler and HttpMethodNotAllowedHandler we've mentioned, ASP.NET provides two others: HttpNotFoundHandler and HttpNotImplementedHandler.

Configuration Hierarchy

With ASP.NET, you can create a web.config file for an application and a unique web.config for each child application. In addition, a machine.config handles global settings for all applications. When handling authorization, ASP.NET handles the various config files cumulatively, starting with the lowest-level child application. In other words, it checks the authorization section from the web.config file of the current application. If there is no match, it checks the authorization section of the machine.config files in any parent applications, eventually ending up in the machine.config file, which, by default, allows access to all verbs and all users. ASP.NET treats the various config files as if you appended the authorization sections from each, starting at the current level and working your way up.

To avoid unintentionally allowing access to a user, it is always a good practice to end each authorization with an element either allowing or denying all users. When ASP.NET encounters this line, it always matches and does not process any more authorization elements. The one exception to this rule is if you want to make one application have a subset of the parent application's authorization settings. In this case, you should carefully plan the parent configuration to prevent unintended access.

TIP

You can prevent a child application from overriding a parent's configuration by adding the allowOverride=“false” attribute to the location element.

Security Policies

Use URL authorization to limit access to Web site resources.

Block unused HTTP verbs using the verbs attribute or HttpMethodNotAllowedHandler.

Use HttpForbiddenHandler or HttpNotFoundHandler to block everyone's access to certain files.

Authorizing Users Through Code

The most flexible aspect of ASP.NET authorization is the ability to authorize users programmatically. There are three ways you can accomplish this task:

Declarative authorization

Imperative authorization

Explicit authorization

Declarative Authorization

Declarative security allows you to set permission demands at the class level as well as on individual methods, properties, or events. You do this by setting an attribute, as shown in Figure 2.16 (C#) and Figure 2.17 (VB.NET), where the methods only allow access to members of the local Administrators group.

Replace all child object permissions with inheritable permissions from this object access denied

Figure 2.16. Declarative Security: C#

Replace all child object permissions with inheritable permissions from this object access denied

Figure 2.17. Declarative Security: VB.NET

Declarative security has the advantage of conveniently setting permissions on selective members or on the class as a whole with a single attribute. The .NET Framework checks declarative security immediately before invoking a method, before it runs any code.

Imperative Authorization

Declarative security allows you to set permissions on a class or its members, whereas imperative security allows you to demand permission from within your code. Figure 2.18 (C#) and Figure 2.19 (VB.NET) demonstrate imperative security.

Replace all child object permissions with inheritable permissions from this object access denied

Figure 2.18. Imperative Security: C#

Replace all child object permissions with inheritable permissions from this object access denied

Figure 2.19. Imperative Security: VB.NET

Explicit Authorization

Similar to using imperative security, you can explicitly check for role membership using the IPrincipal.IsInRole method. The primary difference between imperative security and explicitly checking role membership is that you can check role membership within your code as an If-Then statement without raising exceptions when access fails. This method is useful, for example, when you're enabling or disabling features based on the current user's role, as shown in Figure 2.20 (C#) and Figure 2.21 (VB.NET).

Replace all child object permissions with inheritable permissions from this object access denied

Figure 2.20. Explicit Authorization: C#

Replace all child object permissions with inheritable permissions from this object access denied

Figure 2.21. Explicit Authorization: VB.NET

Code-based authorization allows you to enforce granular security checks throughout your application. For the best protection, use a combination of declarative, imperative, and explicit authorization techniques.

Security Policies

Use declarative, imperative, and explicit role checks to provide multiple layers of authorization.

If utilizing the .NET Framework, you should implement robust declarative authorization techniques.

How do I change permissions on all child objects?

In the Security tab of the Properties dialog box, click Advanced to display the Advanced Security Settings dialog box shown previously in Figure 21-17. Select Replace Permission Entries On All Child Objects With Entries Shown Here, and click OK.

How do I change permissions Access Denied?

How to fix Access is denied message on Windows 10?.
Take ownership of the directory. ... .
Add your account to the Administrators group. ... .
Enable the hidden Administrator account. ... .
Check your permissions. ... .
Use Command Prompt to reset permissions. ... .
Set your account as administrator. ... .
Use Reset Permissions tool..

How do I enable inheritance on all subfolders?

Open the Security dialog for the folder that you want to enable inheritance on. Click Advanced. The Advanced Security Settings dialog opens: Click Enable Inheritance.

What is inheritance permissions?

Inherited permissions are permissions that are given to an object because it is a child of a parent object.