ASP.NET Security Overview


Having briefly overviewed the security features provided by the operating system and IIS, the next step is to understand how these relate to the security features available within ASP.NET. As mentioned earlier, the process of authenticating users and authorizing their requests for resources is like a chain. The operating system and IIS have their own unique parts to play initially, as the request arrives at the server. Afterwards, providing that access is not denied by IIS, the request is passed to ASP.NET for processing and fulfillment.

The ASP.NET Security Process

The schematic in Figure 14-12 shows the process for an ASP.NET request in more detail.

click to expand
Figure 14-12:

After IIS has checked the user's IP address and domain to ensure that they are allowed access, it authenticates the user. Remember that the user may be the IUSR account (the IIS anonymous account) if anonymous access is enabled. At this point IIS spawns an instance of the ASP application that holds the resource the user requested , or passes the request into an already executing instance of the application.

ASP.NET Impersonation

The first step in ASP.NET is to see if the application is configured to use impersonation . This is a similar concept to the way that IIS impersonates users with its anonymous account. However, in this case, impersonation is used to decide whether the user's request should be executed under the context of their account, or that of the special account that ASP.NET uses for anonymous requests.

This is confusing at first. The added complexity comes from the fact that ASP.NET uses the dynamic compilation features of the .NET Framework. It needs to write to the drive in various places to create temporary files and compiled assemblies. The IUSR account has only limited permissions on the local machine, and so is not suitable without some reconfiguration. This is intentional because it is also the account used by IIS to access resources like HTML pages, documents, and zip files that are not executed as part of the .NET Framework.

Note

The account that is actually used for executing ASP.NET resources when impersonation is not enabled is controlled by the <processModel> element in the machine.config configuration file. The username and password attributes specify which account is used. The defaults for normal use are userName="machine" and password="AutoGenerate" . We'll look at this topic in more detail at the end of the chapter.

If impersonation is enabled in an ASP.NET application:

  • If anonymous access is enabled in IIS (the default) the request is made under the context of the IIS anonymous access account ( IUSR_machinename by default).

  • If anonymous access is not enabled in IIS, the request is made under the context of the authenticated user (their own Windows account).

  • In either case, permissions for the account are checked in the Windows ACL for the resource(s) the user requested, and the resource is only available if the account is valid for that resource.

If impersonation is not enabled in an ASP.NET application (the default), then the request is made under the context of the ASP.NET process account, irrespective of whether anonymous access is enabled or not in IIS. This may be the ASPNET or the NETWORK SERVICE account, depending on the operating system version.

Other security checks are also possible within ASP.NET. The availability of these checks depends on the type of security specified. We'll overview the various options next, and look at these in more detail as we go through the chapter.

Windows Server 2003 and IIS 6.0

With the release of Windows Server 2003, Microsoft has made fundamental changes to the way that IIS works. The new version, IIS 6.0, uses application pools to provide a more scalable and robust architecture compared to previous versions of IIS. The accounts that are used to process requests are also changed in IIS 6.0 compared to earlier versions.

In versions of IIS up to 5.0, ASP.NET resources are accessed under an account named ASPNET. This account is created automatically on the machine when ASP.NET is installed, and given permission to access the services, files, and folders it requires in order to execute ASP.NET pages. When ASP.NET spawns a worker process, this process runs under the LOCAL SYSTEM account.

In IIS 6.0, by default, ASP.NET applications run within one or more application pools (unless you specify otherwise , they run within the default pool for the wwwroot folder and the Default Web Site). Worker processes for the application pools run under a new account called NETWORK SERVICE, which has reduced permissions compared to the LOCAL SYSTEM account. However, as you saw earlier in this chapter (in the section User Groups ), there is an account group created named IIS_WPG, of which all the accounts required by ASP.NET are members .

This means that you have to configure access to resources based on which operating system you are using. In Windows 2000, Windows XP and Windows NT4 you configure permissions for the ASPNET account. In Windows Server 2003, in the default configuration for IIS 6.0, you configure permissions on resources either directly for the NETWORK SERVICE account, or for the IIS_WPG group so that it applies to all accounts that ASP.NET uses. The latter is the recommendation in the documentation for IIS 6.0.

Application Pools in IIS 6.0

It's clear from the earlier discussions of IIS 6.0 that application pools change the way that IIS behaves. In the IIS Manager snap-in tool for IIS 6.0, you will see a new entry Application Pools in the left-hand tree view. The DefaultAppPool entry denotes the default application pool that is created by IIS, and depending on what other software you have installed you may see others as well (such as MSSharePointAppPool if you have Microsoft SharePoint installed).

All the applications in the same application pool run within the same process space. However you can create more application pools, as required, and allocate your applications to them so that they run in separate process spaces. Just bear in mind that each one uses a separate block of resources, so it's likely that you'll want to run several applications within each pool, and hence divide the pools in such a way that you achieve the best combination of performance and protection.

However, application pools do attempt to minimize resource usage by recycling applications that are not in use. The Properties dialog for each application pool offers a range of configuration options under the Recycling and Performance tabs. You can also specify which process account the applications within each pool will run under.

As shown in Figure 14-13, the Identity page of the Properties dialog allows you to choose a pre-defined service account (the default is Network Service), or specify any other account. The IWAM_machinename account is pre-filled as an option if you wish to use this.

click to expand
Figure 14-13:
Creating a New Application Pool

Creating new application pools is simply a matter of selecting the appropriate menu option, as shown in Figure 14-14, and specifying a name . You can also save an application pool as a template on which to base new application pools (not shown here), or back up and restore the configuration of the application pools and then use the backups to create new application pools (the from file option shown in Figure 14-14).

click to expand
Figure 14-14:
Note

If you want to run multiple versions of ASP.NET on the same machine, you must create separate application pools for them. If you try and run two applications that execute under different versions of ASP.NET in the same application pool, you'll get a Server Unavailable error message in the resulting web page, and a message in Windows Event Log indicating the problem in more detail.

Selecting the Application Pool for an Application

You can select which application pool an application will run under in IIS 6.0 using the Application pool drop-down list in the Directory or Home Directory page of the Properties dialog for the application as shown in Figure 14-15. This list contains all the application pools that are currently configured in IIS 6.0 on the server.

click to expand
Figure 14-15:
Running IIS 6.0 in IIS 5.0 Compatibility Mode

If you wish, perhaps because your application uses components or resources that require complete ASP.NET version 1.0 compatibility as regards the process accounts, you can run IIS 6.0 in a mode that makes it compatible with IIS 5.0. All applications then run under the same processes as they would in IIS 5.0, and the ASPNET account is used instead of the NETWORK SERVICE account for access to resources by ASP.NET.

To select this mode, open the Properties dialog for the Web Sites entry in the left-hand tree, and go to the Service tab as shown in Figure 14-16. Note that IIS 5.0 isolation mode can be selected only for the complete WWW Service (the complete server), and not for individual applications or web sites. Also bear in mind that this mode is recommended only if you definitely cannot use IIS 6.0 default mode. It is not as robust, hits performance, reduces scalability, impinges on security, and negates the many advantages of true process separation.

click to expand
Figure 14-16:

Web Service Extensions in IIS 6.0

Another area where configuration of ASP.NET differs between IIS 6.0 and previous versions is in a new feature called Web service extensions. IIS 6.0 controls access to resources for all requests based on the file type (defined by the file extension). IIS Manager contains a section that allows you to configure Web service extensions, allowing or prohibiting files of each specific type (see Figure 14-17).

click to expand
Figure 14-17:

If the extension is prohibited , the client receives a 404 Not Found message when they try and access a resource with that extension. This security measure protects the server, as it simply appears to the user that the specific file they requested does not exist. There is no external indication that it is in fact blocked by the web service extension.

When you install ASP.NET on Windows Server 2003, it creates a web service extension for that particular version. However, you will usually have to go to the IIS Manager and enable it using the Allow button shown in Figure 14-17.

If you are unable to access any ASP.NET files, this is the first place to check. And if you have multiple versions of ASP.NET installed, there will be a separate web service extension for each one, so you can Allow or Prohibit individual versions if required.

Creating a New Web Service Extension

If the required web service extension does not exist, you can create one using the Add a new Web service extension link in the page shown in Figure 14-17. This link opens another dialog, as shown in Figure 14-18, to which you add a reference to the resource that will handle requests for files with this extension or of this type. With ASP.NET, as mentioned before, you can set up web service extensions for different versions.

click to expand
Figure 14-18:

Afterwards the new extension appears in IIS Manager, as shown in Figure 14-19. Because the checkbox marked Set extension to Allowed is set in the dialog shown in Figure 14-18, the new web service extension is set to Allowed automatically:

click to expand
Figure 14-19:

The ASP.NET Security Options

ASP.NET provides a range of different options for implementing security and restricting user access in a web application. All these options are configured within the web.config file located in the root folder of the application. The main features of web.config and its usage were discussed in Chapter 13. In this chapter, we'll focus on just the authentication and authorization sections.

Important Points When Using Security in ASP.NET

Before you get too engrossed in the following ASP.NET security examples, there are a couple of things to keep in mind:

  • You don't have to change any of the default settings in Internet Services Manager, or change the permissions assigned to files or resources when using the security features that are configured for ASP.NET in the web.config file. The examples in this chapter work fine with the default settings. However, you can tighten security by editing these settings as well , as we describe in the following chapters when looking at the various configuration options.

  • Many of the options you configure within web.config are applied automatically to any directory in which you place the web.config file. This applies to the authorization settings you make in the <authorization> section. However, this is not the case with the authentication security configuration settings in the <authentication> section. To use the authentication techniques described here, you must place the web.config file in the root folder of a web site (the Home Directory) or configure the directory that contains the web.config file as a virtual root or virtual application in Internet Services Manager. Afterwards, remember to access the application through this alias.

The Types of Authentication and Authorization

ASP.NET itself provides three types of authentication and authorization , though the first of these options (Windows) does rely on IIS to do all the work for you. The four options are shown in the following table:

Type

Name

Description

Windows built- in authentication

Windows

The initial authentication is performed by IIS through Basic, Digest, or Integrated Windows authentication. The requested resources are then accessed under the context of this account. The web.config file can specify the accounts that are valid for the whole or parts of the application.

Passport-based authentication

Passport

This option uses a centralized Web-based authentication service provided by Microsoft, which offers single-sign-on (SSN) and core profile services for member sites.

Forms-based authentication

Forms

Unauthenticated requests are automatically redirected to an HTML form page using HTTP client-side redirection. This is similar to custom authentication methods used in previous versions of ASP, but it provides much of the functionality as part of the framework of ASP.NET. The user provides their login credentials and submits the form. If the application authenticates the request, the system issues a cookie that contains their credentials (in fact, a key for re- acquiring the identity). The client browser then sends the cookie with all subsequent requests, and the user can access the application while they retain this cookie.

Default (IIS) authentication

None

The default. Impersonation can still be used, but access control is limited to that specified within IIS. Resources are accessed under the context of the ASP.NET process account, or the IUSR account if impersonation is enabled.

To specify the type of authentication you want to use in an ASP.NET virtual application or virtual directory, provide the Name shown in the <authentication> section of the web.config file for that site of directory, as shown in the following code:

  <configuration>   ...   <system.web>   <authentication mode="WindowsPassportFormsNone">    authentication options used for the application    </authentication>   <authorization>    users and roles that have access to the application    </authorization>   <identity>    if application should run under a different account    </identity>   </system.web>   ...   </configuration>  

The other two elements within the <system.web> section of web.config that we're interested in are used to specify the details of how authentication should be carried out. The <authorization> section is used to specify which users or groups can and cannot access the application. The <identity> section is used to specify if impersonation is enabled “ in other words, whether to run under the user (or IUSR) account, the ASP.NET process account, or a different account that you specify. You'll see how to use these sections of the file when you look at each type of authentication in more detail next.

Using Windows Authentication in ASP.NET

Windows authentication is best suited to situations like a corporate Intranet web site or web application where you know in advance which users will be accessing your site. This is because you have to set up an account within Windows for each user, and provide them with the username password (the login credentials) they'll need to access the site. Of course, in an Intranet scenario, or an application where you can classify users into groups, you can set up an account for each group and allow all users who know the relevant username and password to access the application under this single account.

Note

Note that we aren't referring to Windows account groups here “ we're using the term 'group' simply to signify several users who will have the same access rights as each other.

An example would be to set up a Windows account named siteadmins , and allow all administrators to log into the application using this account. Just bear in mind that this will not allow you to audit the actions of each individual user, as they will all be accessing resources under the same account credentials. However, this can be a suitable solution in many scenarios.

Setting Up Windows Authentication

To set up an application or a section of an application to use Windows authentication, simply specify this authentication mode and then turn on impersonation within the <identity> element. Now each user will access resources under the context of the account that they logged into IIS with. The <identity> element is only used with Windows authentication, and not with the other types of authentication that we'll meet later.

  <configuration>   ...   <system.web>   <authentication mode="Windows" />   <identity impersonate="true" />   </system.web>   ...   </configuration>  
Specifying Users and Groups

As well as simply specifying Windows authentication, you can also provide a list of users and groups that will be able to access the application. This is done within the <authorization> section of the web.config file, with a series of <allow> and <deny> elements. The general form of each of these elements is shown in the following code:

  <allow roles="  comma-separated list of Windows account group names  "   users="  comma-separated list of Windows user account names  "   verb="GETPOSTHEAD"   />     <deny roles="  comma-separated list of Windows account group names  "   users="  comma-separated list of Windows user account names  "   verb="GETPOSTHEAD"   />  

The <allow> and <deny> elements must contain either a roles or a users attribute. They do not have to contain both, and the verb attribute is always optional. To specify a domain user account, include the domain name followed by a backslash and the username, for example MyDomainName\MyUserName . There are also special values that refer to built-in account groups, such as Everyone , BUILTIN\Administrators , etc.

To specify a local (machine) account you can just use the machine name in place of the domain name. There is no way to specify a domain account without the actual domain (there is no short-cut that means 'use the local domain'), so you have to edit the list if you change the domain name or move the application to another domain.

There are also two special symbols that you can use:

  • An asterisk ( * ) means all users , roles , or verbs , depending on the attribute it is used in.

  • A question mark ( ? ) means 'anonymous access'. In the case of Windows authentication, this is the account set up in IIS for anonymous access. This character can only be used within the users attribute.

The default configuration for a server is in the file machine.config , stored in the directory C:\WINNT\Microsoft.NET\Framework\[version]\CONFIG\ . It contains a single <allow> element that permits all users to access ASP.NET resources:

  <authorization>   <allow users="*" />   </authorization>  

The <allow> and <deny> elements are merged for all configuration files in the application path , starting with the root (default) configuration file machine.config , and including all web.config files in folders below this application directory. Rules that are higher up in the hierarchy (that is, nearer the application directory) take precedence over those in web.config files below them (nearer the root).

Once the merged list of <allow> and <deny> elements is created, they are processed from top to bottom and the best match for a user or role is selected. Processing doesn't just stop when the first match is found, but continues throughout all the entries fine-tuning the selection. This means that a specific reference to a user will take precedence over a role , and over a wildcard rule that uses the asterisk character. The merge process also gives <deny> elements precedence over <allow> elements, so that you can allow a Windows account group using <allow roles=" xxxx "/> , but deny specific users that are within that account group using <deny users=" yyyy "/> .

So, to control access to a specific application or a directory within an application, add a web.config file to that directory. For example, the <authorization> element shown in the following code permits access to the application for the domain-level account named billjones from the domain named MyDomainName and the local (machine) account named marthasmith, plus all members of the domain- level account group named SalesDept. All other users will be denied access.

  <configuration>   ...   <system.web>   <authorization>   <allow roles="MyDomainName\SalesDept"   users="MyDomainName\billjones,MyMachineName\marthasmith" />   <deny users="*" />   </authorization>   </system.web>   ...   </configuration>  
Important

The <allow> element should always be located before the <deny> element.

Specifying HTTP Access Types

You can also use the <allow> and <deny> elements to control the type of HTTP action that a user can take when accessing an application or directory by using the verb attribute. The example shown in the following code allows the domain-level account named marthasmith to send POST requests to the application (submit an HTML form), but all other users will only be able to send GET requests. And, of course, you can combine this access control setting with the list of groups and users, by adding the verb attribute to the previous example that used the roles and users attributes.

  <configuration>   <system.web>   <authorization>   <allow verb="GET" users="*" />   <allow verb="POST" users="MyDomainName\marthasmith" />   <deny verb="POST" users="*" />   </authorization>   </system.web>   </configuration>  

You can also use the <location> element to specify more than one <system.web> section, applying each of these sections to a specific path or file. This is useful for setting different permissions for subfolders or files using a single web.config file. For example, the following code shows how you can specify that a file named mypage.aspx will have different authorization settings from the rest of the files in the same folder:

  <configuration>   ...   <system.web> <!-- default for this application -->   <authorization>   <allow verb="GET" users="*" />   <allow verb="POST" users="MyDomainName\marthasmith" />   <deny verb="POST" users="*" />   </authorization>   </system.web>   <location path="mypage.aspx"> <!-- only applies to this file -->   <system.web>   <authorization>   <allow verb="GET" users="*" />   <allow verb="POST" users="MyDomainName\billjones" />   <deny verb="POST" users="*" />   </authorization>   </system.web>   </location>   ...   </configuration>  
Running Under Another Specific Account

Finally, you can instruct ASP.NET to access resources under a specific account, rather than the user account that was authenticated by IIS or the special ASP.NET process account (which is normally used when impersonation is not enabled).

Here you're specifying that impersonation is enabled but, instead of using the ASP.NET process account, ASP.NET should access all resources under the context of the domain-level account named MyUserName from the domain named MyDomainName . You also have to provide the password for the account so that ASP.NET can present it to the operating system and other applications and services when it requires access to them.

  <configuration>   ...   <system.web>   <identity impersonate="true"   userName="MyDomainName\MyUserName   password="MyPassword" />   </system.web>   ...   </configuration>  
Important

Remember that the password will be visible in the file, and this could introduce a security risk.

IIS and Windows Security Settings for Windows Authentication

Remember that access control using the Windows authentication method depends on a Windows account being available for ASP.NET to use to access the requested resources. You can tighten security by using the ACLs on resources to allocate permission to just specific users, or to the accounts that the user will be running under. This isn't required, but does provide a second level of protection.

To be able to do this, you must be aware of which account is actually being used to access the resource, and give that account the appropriate permissions while removing any permissions that are not required. The schematic in Figure 14-20 shows which accounts you must set permissions for, depending on the configuration in your machine.config and web.config files:

click to expand
Figure 14-20:
The Logon Process in Windows Authentication

When you access a resource in a secured application or virtual directory that does not allow anonymous access, you are always required to log on. However, if you are accessing the application or directory from the local machine or a machine on the same domain, you may not actually see the logon dialog. This is because “ providing Integrated Windows authentication is enabled in Internet Services Manager (the default) “ your browser will send your current Windows logon details in response to the logon challenge from the web server.

So, it's a good plan if you are building applications for the web (rather than for a corporate Intranet) to access the site from a machine that is not logged into the domain, as well as experimenting with one that is. On a machine that is not on the same domain (and not on a trusted domain), you will see the standard logon dialog, as shown in Figure 14-21:

click to expand
Figure 14-21:

One useful way that you can tell what's going on as far as IIS authentication is concerned is to look at the page you get back if you make three attempts to access a secured resource with an invalid username or password. If anonymous access is not enabled in IIS, you get the standard IIS error page, as shown in Figure 14-22. This is because you have failed the IIS logon process.

click to expand
Figure 14-22:

However, if anonymous access is enabled within Internet Services Manager (the default), you are granted access and the request is passed to ASP.NET. It then detects that you don't have permission to access the resource (because your Windows account username and/or password are invalid) and it sends back its own error page, as shown in Figure 14-23. Later on in this chapter, we'll see an example of Windows authentication that you can use to help configure your applications and virtual directories.

click to expand
Figure 14-23:

Using Passport Authentication in ASP.NET

Windows authentication provides the most secure way of controlling access and securing your ASP.NET applications. However, it falls down if you want to establish a single-sign-on policy for several applications that are distributed across different servers and sites “ especially if these are geographically separated. The only solution is to set up the same accounts on all the servers, perhaps by establishing a Windows 2000 forest using Active Directory so that all the servers are part of the same enterprise “ even if they are on different domains.

But even this fails if you want to enable a system where users can be authenticated using the same credentials across multiple sites that you don't provide yourself. For example, you might want to build a solution where a user can log onto one of the well-known sites like hotmail.com and then come to your site and be automatically authenticated based on the logon credentials they provided when they logged onto Hotmail.

This is possible using Passport authentication . Microsoft provides a Passport Service that can be used to authenticate users on any passport-enabled site, anywhere on the Internet. When they log onto a participating site, their browser or user agent sends their credentials to the passport service, which authenticates them and places a secure cookie on their machine. Then, when they access another participating site, the browser presents this cookie to the passport service to prove that the user has already been authenticated. The passport service then indicates who that user is to the new site so they can be properly authorized “ that is, the new site can check if this user has permission to access the resource they've requested.

So, the power of the passport service is that a user can present the same credentials to any participating site, while only having to log in once during a session. When they close their browser, or indicate that they wish to log off, the cookie is destroyed . They must then log on again to re-access resources on any of the participating sites.

Setting Up Passport Authentication

Unfortunately, passport authentication doesn't come free “ someone has to pay the running costs of the service. To set up passport authentication you must subscribe to the service, and install special software on your Web server to allow the process to work. Full details are available from http://www.microsoft.com/net/services/passport/business.asp.

Once you've installed the software and subscribed to the service, you configure passport authentication in the web.config file, as shown in the following code. The <passport> section supports a single attribute named redirectUrl . The default value (before you install and configure passport authentication) is internal , which means that unauthenticated requests will receive a generic error message created by your server. Any other string is assumed to be the URL of the passport service that unauthenticated requests will be redirected to for authentication.

  <configuration>   ...   <system.web>   <authentication mode="Passport">   <passport redirectUrl="internal  url  " />   </authentication>   </system.web>   ...   </configuration>  

Once passport authentication is enabled, the login process to your server goes something like this:

  • The user requests a protected resource from your server. If they have already logged into the passport service, there will be an encrypted ticket in a cookie or the query string, and your server will access the passport service to get the user's identity.

  • If there is no ticket, or if it has expired or is invalid, they are redirected to the passport service's login page on the main passport service servers. They present their credentials, are authenticated, and are redirected back to your server with an appropriate ticket.

  • Your server can now check the user's authorization and provide the protected resource if they have the relevant permission.

Using Forms-based Authentication in ASP.NET

The third type of authentication available in ASP.NET is an excellent solution for applications where the highest levels of security are not required. Forms-based authentication (sometimes referred to as cookie- based authentication) automates many of the tasks that you would normally perform in earlier versions of ASP to build custom authentication solutions. Forms-based authentication also removes the unintuitive Windows Logon dialog, allowing you to replace it with an attractive custom form, or integrate the login controls (basically two text boxes and a button) into existing pages.

The schematic in Figure 14-24 describes the process. As usual, the request is received by IIS, which checks that the IP address and domain of the user are permitted. IIS also authenticates the user if anonymous access is disabled, although in this scenario you will almost always allow anonymous access because the access control is being performed by ASP.NET. Once IIS is happy with the user's request, it passes it to ASP.NET, where the first step is to see if there is an authentication cookie within the request headers.

click to expand
Figure 14-24:

The forms authentication process generates this cookie when the user logs into the application. If it's present, you know that they have already been authenticated and the cookie contains their identity. ASP.NET then checks whether this user is authorized to access the resource they requested, and if so sends it to them. If not, the user is denied access.

If the cookie is not present in the request headers, the user is automatically redirected to a custom login page that you create yourselves. The user enters their credentials into this login page and submits it to your application where these credentials are automatically checked to authenticate the user. If they are recognized, an authentication cookie is added to the headers and the request is sent to the next stage of the process. ASP.NET checks to see if this user is authorized to access the resource they requested, and if so sends it to them. If not, they are denied access.

Setting Up Forms-Based Authentication

Like all other ASP.NET security settings, forms-based authentication is configured within the web.config file for an application or a virtual directory. As shown in the following code, the <authentication> section carries the value " Forms " for the mode attribute, and within the element itself you can add more elements to specify how the authentication of users will behave:

  <configuration>   ...   <system.web>   <authentication mode="Forms">   <forms name="  cookie-name  "   path="  cookie-path  "   loginurl="  url  "   protection="AllNoneEncryptionValidation"   timeout="  number-of-minutes  "   requireSSL="truefalse"   slidingExpiration="truefalse" >   <credentials passwordFormat="ClearSHA1MD5">   <user name="  user-name  " password="  user-password  " />   <user name="  user-name  " password="  user-password  " />   ... more users listed here ...   </credentials>   </forms>   </authentication>   <machineKey validationKey="AutoGenerate[,IsolateApps]  key  "   decryptionKey="AutoGenerate[,IsolateApps]  key  "   validation="SHA1MD5"/>   </system.web>   ...   </configuration>  

The attributes of the <forms> element define:

  • The name that will be assigned to the cookie.

  • The path that the cookie is valid for. This is usually set to " / " to indicate the complete site. If not, and the site contains links that are not in the correct letter case (for example an <a> element with href="mypage.aspx" where the actual page name is MyPage.aspx ), then the cookie will not be returned by some browsers. This will cause the login form to be displayed again.

  • The loginurl that specifies the virtual path to the login form page.

  • The protection level required for the cookie. The settings are.

    • All (the default), which uses both data validation (based on the <machineKey> element) and encryption (Triple DES if available and if the key is at least 48 bytes long)

    • None (should be used only for personalization purposes)

    • Encryption (the cookie is encrypted but data validation is not performed)

    • Validation (validation is performed but the cookie is not encrypted)

  • The timeout in minutes before the cookie expires on the user's machine and the server.

  • The requiresSSL value can be set to true to force the use of SSL for any pages that pass the authentication cookie across the wire. The default is false . This feature was added in version 1.1.

  • The slidingExpiration value determines if sliding expiration is used. When true (the default), each access to a secured page resets the timeout. When false , the timeout is enforced from initial login. This feature was added in version 1.1.

Within the <forms> element is an optional <credentials> element that specifies the encryption algorithm used to encrypt the user's password in the web.config file. Within this element there can be a series of optional <user> elements, which between them specify the users who will be able to access the protected resources.

Specifying Encryption and Validation Key Generation Methods

You can also specify an optional <machineKey> element within the <system.web> section, which specifies the keys and method to be used to encrypt the cookie contents. In general you will omit this element and allow a key to be created automatically. However, it can be useful in a situation like a web farm, where you want all machines to use the same key. The key length must match the number of characters required for the encryption level and method that is used. The entry in the default machine.config file (in the following code) specifies that the keys are auto-generated:

  <machineKey validationKey="AutoGenerate,IsolateApps"   decryptionKey="AutoGenerate,IsolateApps"   validation="SHA1" />  

Notice the IsolateApps modifier (suffix) on the validationKey and decryptionKey attribute values. These are new in version 1.1 of ASP.NET, and cause the auto-generated keys to include details of the ASP.NET application that is using Forms authentication (and which is creating the cookie) within the key that is generated. This improves security and application isolation, especially where a server is hosting multiple sites or applications that are not supposed to be able to share authentication cookies.

In reality, it means that different applications using Forms authentication, running on the same machine, will generate different keys for securing their cookies, rather than all using the same key (as was the case in version 1.0). However, the only times that this new behavior is likely to affect your applications are:

  • Where you rely on shared authentication cookies, perhaps where you have nested applications (an application within a subfolder of another application, with the Path of the cookie set to "/" in the local web.config file).

  • Where you are passing the viewstate in a page to a different application through some kind of customized form-post. This is because the values in the <machineKey> element are used to validate and encrypt the viewstate string that is inserted into a hidden control when an ASP.NET server-side <form> is used.

To retain the version 1.0 behavior when running under version 1.1 of the .NET Framework, you can:

  • Remove the IsolateApps modifiers from machine.config , or (better) use a local web.config file that does not contain the IsolateApps modifiers. This gives behavior that is identical to version 1.0.

  • Change the validationKey and decryptionKey attribute values to specify an explicit key, rather than auto-generating it. If you are using a web farm or other shared server setup to drive the site, you will be using a specific key that is the same on all the servers anyway, and so the behavior will be identical to version 1.0.

An Example: Forms-Based Authentication Configuration

So, an example web.config file might look like that shown in the following code. Remember that the <credentials> and <machineKey> sections are optional. The example shown also lists some users, and you can see that the passwords are encrypted in this case. You'll see where you get these values from later in the chapter.

  <configuration>   ...   <system.web>   <authentication mode="Forms">   <forms name="MyNewApp" path="/" loginUrl="/main/login.aspx"   protection="All" timeout="30" >   <credentials passwordFormat="SHA1">   <user name="billjones"   password="87F8ED9157125FFC4DA9E06A7B8011AD80A53FE1" />   <user name="marthasmith"   password="93FB8A49CC350BAEB2661FA5C5C97959BD328C50" />   <user name="joesoap"   password="5469541CA9236F939D889B2B465F9B15A09149E4" />   </credentials>   </forms>   </authentication>   <!-- keys usually only specified for a Web farm -->   <machineKey validationKey="3875f9...645a78ff"   decryptionKey="3875f9...645a78ff"   validation="SHA1" />   </system.web>   ...   </configuration>  
Note

The <identity> element is not used in forms-based authentication.

Creating a Login Form

After you've completed the configuration tasks with web.config , what about the things you have to do as developers to complete the setup of forms-based authentication? You need a form that will be used to collect the user's credentials, and code to process these credentials. The following code shows a simple example of the HTML section of the page:

  <%@Page Language="VB" %>   <html>   <body>     <form runat="server">     UserName: <input id="txtUsr" type="text" runat="server" /><p />   Password: <input id="txtPwd" type="password" runat="server" /><p />   <ASP:CheckBox id="chkPersist" runat="server" />   Remember my credentials<p />   <input type="submit" value="Login" runat="server"   onserverclick="DoLogin" />   <div id="outMessage" runat="server" />   </form>     </body>   </html>   ... script section goes here ...  

This creates a login form page containing textboxes for the username and password, and a checkbox where the user can specify whether their credentials are to be remembered so that they won't have to login again next time they visit the site. Next there is a Login button that fires an event handler named DoLogin on the server, followed by a < div > element where you display a message if the user's credentials are incorrect. The visual appearance of the page can be seen in Figure 14-25:

click to expand
Figure 14-25:
Important

To prevent the user's credentials being passed over the network in clear text, you should consider storing this form in a directory that has SSL (HTTPS) enabled. Once they are validated , the encrypted cookie can be used in the application over HTTP as usual. The content of the authentication cookie is just the encrypted session ticket “ it does not contain the username or password.

Writing the Login Code

While forms-based authentication is a clever technology, it can't do everything automatically. You have to write code that authenticates the user and performs the other operations required, such as creating the cookie and redirecting the user to the page they originally requested. However, this is very simple.

All the classes used in ASP.NET security are in the System.Web.Security namespace of the class library. The class that handles forms-based authentication is called FormsAuthentication , and it exposes a range of Static methods and properties that you can use in your code. The most common methods are shown in the following table:

Method

Description

Authenticate ( userid , password )

Checks to see if a username and password combination is valid by comparing it to the set of users specified within web.config . Returns True or False .

Decrypt ( string )

Returns an instance of a FormsAuthenticationTicket class, given a valid encrypted authentication ticket obtained from an HTTP cookie as a String .

Encrypt ( ticket )

Returns a String containing an encrypted authentication ticket suitable for use in an HTTP cookie, given a FormsAuthenticationTicket .

GetAuthCookie ( userid , persistent ) GetAuthCookie ( userid , persistent , path )

Returns the authentication cookie without adding it to the response headers. This is useful if when customizing the cookie before issuing it (for example changing the path it applies to). Takes the user ID or name, a Boolean value to specify if the logon will be persistent, and optionally a path for the cookie.

GetRedirectUrl ( userid , persistent )

Returns the URL of the original page that the user requested before being redirected to the login page. Can be used in conjunction with SetAuthCookie to provide custom authentication when the RedirectFromLoginPage method is not being used. Accepts the user ID or name and a Boolean value to specify if the logon will be persistent.

HashPasswordFor Storing InConfigFile ( password , hash-type )

Creates and returns a String that is the encrypted values of a password, using the specified hash type (" SHA " or " MD5 ").

RedirectFromLoginPage ( userid , persistent ) RedirectFromLoginPage ( userid , persistent , path )

Performs all the actions required once a user has been authenticated, including: creating the encrypted cookie, adding it to the request headers, and redirecting the user to the page they originally requested. Takes the user ID or name, a Boolean value to specify if the logon will be persistent, and optionally a path for the cookie.

RenewTicketIfOld ( ticket )

Takes a FormsAuthenticationTicket and returns it with the sliding expiration conditionally updated.

SetAuthCookie ( userid , persistent ) SetAuthCookie ( userid , persistent , path )

Creates the encrypted cookie, and adds it to the headers, but doesn't redirect the user. Allows the tasks normally accomplished by the RedirectFromLoginPage method to be performed individually, and tailored to a particular situation. Takes the user ID or name, a Boolean value to specify if the logon will be persistent, and optionally a path for the cookie.

SignOut

Destroys the current encrypted cookie, effectively logging the user out of the application.

The following table lists the read-only static properties of the FormsAuthentication class:

Property

Description

FormsCookieName

Returns the name for the cookie as configured for the current application as a String .

FormsCookiePath

Returns the path of the cookie as configured for the current application as a String .

RequireSSL

Returns a Boolean value indicating whether a cookie must be transmitted only over a secure connection. Added in version 1.1.

SlidingExpiration

Returns a Boolean value indicating whether sliding expiration is enabled for the cookie as configured for the current application. See the section How Long Is a Login Valid For? later in this chapter for more details. Added in version 1.1.

So, to authenticate your user and return them to the page they originally requested, you just need to create an event handler that is executed when the Login button is clicked. In your login form, you specified the subroutine DoLogin as the value of the onserverclick attribute of the login button. Let's start by checking to see if the username and password that were provided are valid within the list of users in web.config . If they are, the Authenticate method returns True and you can call the RedirectFromLoginPage method to create the cookie, add it to the request headers, and redirect the user to the page they originally requested. It's as simple as that.

  Sub DoLogin(objSender As Object, objArgs As EventArgs)   If FormsAuthentication.Authenticate(txtUsr.Value, txtPwd.Value) Then   FormsAuthentication.RedirectFromLoginPage(txtUsr.Value, _   chkPersist.Checked)   Else   outMessage.InnerHtml = "<b>Invalid credentials</b> please re-enter."   End If   End Sub  
How Long Is a Login Valid?

One interesting point is how long the authentication cookie will be valid for. If you don't specify a value for the timeout attribute in the <forms> element in web.config , the cookie will only remain on the user's machine for 30 minutes (the default setting in machine.config ), or until they close their browser. However, you can set the timeout attribute in the <forms> element to over ride this setting.

This means that they will be able to leave the site and come back to it again within 30 minutes providing that they haven't closed their browser (or deleted the cookie). Of course, as the user accesses pages within the site, the cookie will be updated with each response from the server, and so the timeout only comes into force the specified number of minutes after the last time they accessed a page. This is called sliding expiration . But, even if they leave their browser running, they will be effectively logged out after the timeout period. This provides a better level of security. You also have the option to persist the cookie between sessions. When you call the RedirectFromLoginPage method, you need to specify a Boolean value for the second parameter. In the example code, this is the value of the Checked property of the checkbox control on the login page:

  FormsAuthentication.RedirectFromLoginPage(  username, persist-cookie  )  

Passing the value True to the method causes it to create a cookie with a long expiry date and time (50 years from now!) so that the user will not have to log back into the site when they return again. Although most modern browsers store cookies on a per-user basis (providing that the client machine is set up to force users to log in), this can present a security risk. It's not difficult to hijack a cookie, and by doing so the hijacker will automatically be granted access to the site during the lifespan of that cookie. Nevertheless, it is a useful feature for low-security or personalization-only scenarios.

Finally, you can expire a cookie immediately on demand by calling the SignOut method. You can place a Log Off button or link on a page, and create an event handler that destroys the cookie and prevents the user accessing any other resources until they log in again. In the event handler all that's needed is:

  FormsAuthentication.SignOut()  

However, if a user has stolen a persistent cookie, this will not detect and remove it. Hence, persistent cookies should never be used for applications other than those performing basic personalization and requiring the minimum level of security.

Authorizing Users with Forms-Based Security

So far, you've only actually authenticated (or identified) the user “ you haven't specified what resources they will be allowed to access. Unless you are happy for any authenticated user to access any of the resources within the site or directory (an unlikely scenario in a secured application), you must include an <authorization> section in web.config as well. If not, the default authorization level specified in the machine.config file (shown in the following code) will be used:

  <authorization>   <allow users="*" />   </authorization>  

To allow only specified users to access the application, add an appropriate <authorization> element to the web.config file for this site or directory. The format and content are the same as we described earlier when looking at Windows authentication and authorization “ and the same rules apply.

Note that you're using the anonymous access wildcard ( ? ) in the <deny> element. In forms-based authentication, this indicates that only users you specifically authenticate will be allowed access. Irrespective of which Windows account the user is running under ( generally it will be the ASP.NET process account in this case), they will only be permitted access if they are in the list of users in the <allow> element.

  <configuration>   ...   <system.web>   <authorization>   <allow users="billjones,marthasmith,joesoap" verb="GET" />   <allow users="marthasmith" verb="POST" />   <deny users="?" />   </authorization>   </system.web>   ...   </configuration>  

You can also get away with using just the single <deny> element that prevents unauthenticated access if you don't want to set any specific access permissions for the users you authenticate. In other words, providing that you are happy for all users that are listed in the <authentication> section to have access to all resources in the application using any type of HTTP method ( POST , GET , HEAD ), you can use the simple configuration setting shown in the following code:

  <authorization>   <deny users="?" />   </authorization>  
Important

Don't be tempted to try and set Windows ACL permissions on resources for the users you specify when using forms-based authentication. Even if Windows accounts do exist for these users, they are not used when the user logs in via forms-based authentication. All access will be performed under the context of the ASP.NET process account (which must have access to the resource).

Custom Lists of User Credentials

All your forms-based authentication configuration examples so far have used the <credentials> section of web.config to store the list of users that you authenticate requests against. In many cases this is not practical. Rather than manually editing a text file to add and remove users, you will often want to store user details elsewhere “ maybe in a database table, an XML document, or even Active Directory. However, it's still useful to be able to take advantage of the other features that forms-based authentication provides, such as automatic redirection to a login page, encryption and validation of the authentication cookie, and integration with the environment (which allows you to retrieve the user's details elsewhere in your code; more details of this coming up later).

It's easy to accomplish lookups of user credentials in other data stores, as the examples at the end of the chapter demonstrate . For example, you can use the relational data access capabilities of .NET to retrieve values from a relational database using SQL statements or stored procedures, or you can use classes from the System.Xml namespace to access XML documents.




Professional ASP. NET 1.1
Professional ASP.NET MVC 1.0 (Wrox Programmer to Programmer)
ISBN: 0470384611
EAN: 2147483647
Year: 2006
Pages: 243

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