Chapter 28. Securing Your ASP.NET Applications

IN THIS CHAPTER

“Security” is a term that is often overused and encompasses so many different topics that it can be confusing. When someone is talking about securing an application, often they are talking about things completely irrelevant to our needs. To distill the concept of security down a bit, the topic of security in this chapter is limited to just the notion of securing an ASP.NET application.

In this chapter, you will learn the important distinction between authentication and authorization. You will learn how to identify the users connecting to your websites as well as how to discern what they can and cannot do. You will also get an introduction to some of the new ASP.NET controls relating to users and security. Finally, you will see how to use and extend the new Membership provider that comes with ASP.NET 2.0.

Security Through Authentication

Regardless of what type of application you are creating in ASP.NET, the chances are very high that you will want to be able to identify the users who are connecting to your website. If you want to do something as simple as provide a personalized greeting or something as complex as identifying the user through some corporate single sign-on system, you will need to make use of some form of authentication. Authentication is the process of identifying who a particular user of your web application is by obtaining some set of credentials from the user and verifying those credentials against some authority. The authority can be a custom database, an Active Directory, or a single sign-on authority such as Microsoft Passport.

Authentication in ASP.NET works on the premise of providers. You choose which provider is providing authentication services for your application through a setting in the Web.config file.

You indicate the authentication provider within Web.config by setting the <authentication> element as follows:

<authentication mode="[Windows|Forms|Passport|None]"/>

Three authentication providers come with ASP.NET: Windows, Forms, and Passport. If you choose “None” for your authentication provider, ASP.NET will not do anything whatsoever to identify the person requesting each page. In the next few sections of this chapter you will see how to use the three authentication providers.

Two main interfaces are used by all of the authentication providers: IPrincipal and IIdentity. These two interfaces allow for a standard method of identifying authenticated users.

When a user has been authenticated (even if that authentication failed), an ASP.NET page has access to the user credentials and other authentication through the web context. All pages have access to the web context through an instance of the HttpContext class, which you can access via the HttpContext.Current property. To obtain an IPrincipal representing the current user, you can make use of the HttpContext.Current.User property.

Windows Authentication

Windows authentication for ASP.NET is provided by the WindowsAuthenticationModule class (found in the System.Web.Security namespace). When a user is authenticated using Windows authentication, the provider will create an instance of the WindowsPrincipal class and make it available through the web context.

Windows authentication works by taking whatever Windows-based credentials (clear text, integrated, and so on) were supplied by Internet Information Server (IIS) and providing them to the ASP.NET application through the WindowsPrincipal and WindowsIdentity classes.

Because Windows authentication is the default authentication provider for ASP.NET, it is extremely easy to create a sample application to test it out. To do so, create a new C# website called Authentication. After you’ve done this, add the following lines of code to the Page_Load event handler of the default Web Form that comes with the application:

Image

The User object is made available to all ASP.NET web pages. If you are writing a server control or a user control, you can access the User object by using Page.User or HttpContext.Current.User. Figure 28.1 shows the output of this page when run under Windows authentication. Obviously the name of the user will change, but everything else should look very similar in your own development environment.

Figure 28.1 The output of a page displaying Windows authentication information.

Image

Passport Authentication

Passport authentication is handled by the Passport authentication provider. Passport is a centralized authentication service provided by Microsoft. Your application benefits in that users can reuse the same Passport on any number of sites while still maintaining their own privacy. Your application, by making use of Passport, can skip a lot of the process usually involved in creating an authentication scheme. If you are developing on Windows Server 2003, you already have all the tools you need in order to work with Passport authentication. If you are not using Windows Server 2003, you will need to download the Passport SDK. For information on the Passport SDK and how to support Passport authentication on your website, go to http://www.passport.com/business. In order to see the documentation you will have to have a Passport of your own.

Much like Forms authentication (covered in the next section), Passport authentication works with cookies. When a user opens a browser to a Passport-secured website, the client’s cookies are examined for a valid Passport authentication ticket. If it is found, the user is seamlessly delivered to the secured resource. If no such ticket is found, the user is redirected to the Passport authentication page hosted by Microsoft. After authentication takes place, the user is then redirected to the original secured resource. Because the user now has a valid Passport authentication ticket, the client is then given access to the protected resource.

The PassportAuthenticationModule detects the presence of a valid Passport and then creates a PassportIdentity instance, which then becomes available from within the User object as shown in the preceding samples.

The PassportIdentity class offers several additional methods and properties that are useful when creating a Passport-secured website. For a full reference on the PassportIdentity class, consult the MSDN documentation at http://msdn.microsoft.com and the Passport SDK, which can be found at http://www.passport.com/business and is included with Windows Server 2003.

Forms Authentication

Forms authentication is the most commonly used means of authentication for public-facing websites. The reason for this is that there are often concerns with securing a website with Windows authentication that must be accessible to users who don’t belong to a domain and to users accessing the site across any number of router configurations, as well as a need for protection of credentials.

As mentioned in the Passport section, Forms authentication is cookie-based. This means that when a user has authenticated to a website, that fact is stored in a cookie on the user’s machine. If the website fails to find an authentication cookie, the user is redirected to a login page where they can supply their credentials (or in some cases they can register a new account).

Forms authentication has several options that can be configured through the Web.config file. The options for the <forms> element in the Web.config file are shown in the following code:

Image

The following is a quick summary of some of the options shown in the preceding example:

  • protection—Indicates the protection used to secure the Forms authentication cookie
  • timeout—Indicates the amount of time (in minutes) that will elapse before a Forms authentication cookie will expire
  • credentials—Allows you to manually specify a list of users who can use your application directly in the web.config file

Also keep in mind that Visual Studio 2005 has a far more active and alert IntelliSense system than previous versions—you will be able to see all of the options available to you while typing directly into the web.config file.

The <forms> element only indicates how you are going to protect the pages on your website, not which locations you plan on protecting. To protect every page in your application except the login page, you can use a web.config file that looks like this:

Image

The authorization section indicates who has been granted access and who has been denied access. The wildcards ? and * indicate anonymous (unauthenticated) users and all users, respectively. You will see more about the authorization element later in the chapter in the section “Security Through Authorization.”

When you use the FormsAuthentication class, several static methods are available to you for dealing with Forms authentication, including the following:

  • RedirectFromLoginPage—This method authenticates the user (saves their cookie) and redirects from the login page back to the original protected resource.
  • RedirectToLoginPage—This method sends the user to the login page, the URL of which is defined in Web.config.
  • HashPasswordForStoringInConfigFile—This method is a handy, quick way of storing a user’s password in an encrypted hash.
  • SetAuthCookie—This method authenticates the user but performs no additional processing (such as redirection to a protected resource).

  • SignOut—This method will expire the current user’s Forms authentication cookie.
  • Authenticate—If you are storing the user credentials in the Web.config, you can use this method to validate a username/password combination against those stored in the config file.

With a quick change to the preceding application and a call to FormsAuthentication.RedirectFromLoginPage, you can create a quick sample of Forms authentication. The three lines of code you used to display the WindowsIdentity details can also be used to show the same information from Forms authentication, as shown in Figure 28.2.

Figure 28.2 Forms authentication in action.

Image

If you have experience with Forms authentication in previous versions of ASP.NET, you may think that this section is a little small. I am deliberately leaving out some of the more tedious programming tasks associated with authentication such as creating login pages, status controls, and so that on. Later in this chapter there is a section (“The ASP.NET Security Controls”) covering a host of new UI controls that automate a great deal of the common tasks associated with authentication that work with any authentication provider, not just Forms.

User Management with Membership

Authentication requires that a set of credentials supplied by the user be validated against some previously stored set of credentials. The means by which you store the user credentials is completely up to you. You can store them in a SQL Server instance, you can store them in an XML file, or an Access database, or even the Web.config file.

Every web application that requires a user to log in must deal with the issue of storing the information about the website’s members and their credentials. ASP.NET 2.0 provides a new API, the Membership API. This API abstracts the management of user storage and credentials in a standard way. As you will find out later in this chapter, there is also a set of standard controls that are fully compatible with the membership API.

The Membership API consists of the set of classes provided by ASP.NET for dealing with Membership that reside in the System.Web.Security.Membership. This API provides the following functionality:

  • User management—Create, edit, and delete users.
  • Membership data management—Maintain membership data, such as email addresses.
  • Authentication—The membership API is capable of validating supplied user credentials against the credentials contained in the membership store.
  • Advanced password management—Not only does the Membership API give you easy access to methods for changing user passwords, but through Membership, users can also retrieve and reset their own passwords.

The bottom line is that now the majority of the tasks you had to code manually each time you created an ASP.NET v1.x website are now bundled for you in a secure, easy-to-use library that is available to every ASP.NET 2.0 web application.

The first step to using Membership on any application is to make sure that the ASP.NET Membership schemas are installed properly. These schemas are installed in an instance of SQL Server, or your default SQL Express instance. If this was not already done for you at the time ASP.NET was installed, you can use the command-line utility aspnet_regsql.exe to do the job for you. You can find this tool in [drive:]windowsMicrosoft.NETFrameworkv[version].

The next thing you need to do is create a connection string for the Membership provider to use. This connection string will be stored in the new <connectionStrings> element in Web.config. If you installed the full version of SQL Server 2005, you will have a standard connection string. If you are using the Express version of SQL 2005, you will have a slightly different connection string. The following is the line of XML I used for my Membership connection string after installing the schemas into my copy of SQL Express:

Image

Note that if you’re using a full version of SQL Server, you should replace the .SQLExpress instance name with the server name (and possible instance name) of your full installation of SQL Server. Next, you need to configure the Membership API from within the Web.config file. The following is a sample Membership provider configuration:

Image

When you look at this configuration, the individual attributes of the <add> element correspond directly to some of the static properties of the Membership class.

Before we get into any serious Membership coding, let’s take a look at some of the properties and methods of the Membership class, which are shown in Tables 28.1 and 28.2.

Table 28.1 System.Web.Security.Membership Properties

Image

Table 28.2 System.Web.Security.Membership Methods

Image

The impact of a standardized membership API is extremely significant. This allows for developers of membership-enabled ASP.NET applications to learn one simple API for managing users, and the only difference between one application and the other is the Web.config setting for the provider and connection string. I can’t stress enough how incredibly useful the new provider model is for ASP.NET developers. Later in this chapter you will see how to create your own Membership provider.

To recap, the following are the steps to take in order to enable Membership in your ASP.NET application:

  1. Verify that the Membership schemas are installed in your database. You can do this with the aspnet_regsql.exe tool.
  2. Add your connection string to the Web.config file.
  3. Set up the <membership> element in Web.config.
  4. Begin using the Membership API and UI Controls.

Security Through Authorization

In the preceding section you saw that regardless of what means of authentication is used, all users will appear to ASP.NET pages as an instance of IPrincipal, which in turn has an Identity property of type IIdentity. Using these standard interfaces, your code can function properly under any authentication scheme. The next section of this chapter deals with the concept of authorization, which is the process by which an authenticated user is permitted or denied access to specific resources. In other words, authentication deals with who a user is, and authorization deals with what the user can do.

Authorization with Roles

As you saw in the preceding section of this chapter, authentication is supported largely by the Membership API and Membership providers like the SQL Membership provider. The Provider model is used throughout ASP.NET to create standard interfaces in commonly used design patterns. Membership is something that virtually every ASP.NET website has to deal with in some form, so the Membership provider was used to standardize how that is done, creating a huge benefit for developers.

Authorization in ASP.NET applications is largely supported by the Role provider. A Role provider is a pluggable provider that gives programmers a standard API for determining users’ role membership as well as manipulating the roles to which users belong. If you use the provider model, the code for your role-based application will be identical whether the user role membership is stored in SQL Server, Access, Active Directory, or some other proprietary data store.

Just as with the Membership provider, you need to tell your application which Role provider you’re using. The first step is to define a connection string. If you followed along with the preceding example, you already have a connection string in your Web.config file. The next step is to define the <roleManager> element. An example of a <roleManager> element is shown in the following code:

Image

Access to the majority of the functionality available through the Role management provider is available through the Roles class. Table 28.3 lists some of the properties of the Roles class and Table 28.4 lists some of its methods that you will be using in your own role-based security implementation.

Table 28.3 Roles Properties

Image

Table 28.4 Roles Methods

Image

As you will see in the next section, working with Users and Roles when using the Membership and Role providers has already been wrapped into a few extremely handy server controls that ship with ASP.NET 2.0. To see how the Role system works program-matically, try walking through a quick sample.

The first thing you need to do is create a user. To create a new user, you can use the Membership.CreateUser method as shown in the following code:

Image

When you have a user, you can start playing around with the Role membership system. For example, the following code creates several new Roles and adds the current user to a few of them:

Image

I can’t stress enough how important the impact of the provider model is. The common tasks of building a Membership and Role system —which most of us have built over and over again for many different ASP.NET applications—have been completely abstracted into a provider model. This allows you to create standardized code that works against a standard Membership and Role system, and you will know that your code will work on any other application that is using the Membership and Role providers.

The ASP.NET Security Controls

One of the things that is possible now through the use of the Membership and Role providers is the creation of a standardized set of controls that provide a customizable user interface for many of the common tasks related to securing an ASP.NET application. With previous versions of ASP.NET, you not only had to create your own Membership and Role system, but you also had to create your own controls for facilitating login, user validation, password entry, display of the currently logged-in user, and much more. This section shows you the new controls that ship with ASP.NET 2.0 that sit on top of the provider model and will drastically reduce the amount of code you have to write and the amount of time you have to spend writing redundant security code.

Login

The Login control is a control that facilitates the prompting for a user’s name and password. In addition, it can display a checkbox that controls whether or not the validation cookie is persistent. To use it, simply create a login page (usually called login.aspx) for your web application and open up the Toolbox. From the Toolbox, in the Login group, drag the Login control onto your form. This control has a host of configurable options. You can customize the appearance of every aspect, you can specify the URLs for icons for each option, you can choose whether to include a link to create a new user, and you have many more choices. Figure 28.3 shows a login control on a form that is fully functional, attached to the default Membership provider, and took just minutes to create.

Figure 28.3 The Login control in action.

Image

LoginName

The LoginName control is a simple control that displays the name of the currently logged-in user, regardless of the means by which they logged in. To use it, just drag it onto the form in the location where you want the user’s name to appear and then change the properties to customize the look and feel as needed. For example:

<asp:LoginName ID="LoginName1" runat="server"
FormatString="Welcome to the site, {0}" />

This will display the text “Welcome to the site, Kevin” if the user name is “Kevin.” If the user is not authenticated, the LoginName control will be empty and not render any text.

LoginStatus

The LoginStatus control indicates the user’s logged-in status by presenting them with a link. If they are logged in, there is a link that will let them log out. If they are logged out, there is a link to let them log in. You can configure the URLs the user will be sent to for each action or use the defaults. As with many of the other controls, all you have to do is just drag this control into the appropriate location from the Toolbox and you’re ready to go. Note that if your application doesn’t allow anonymous access to the page on which the LoginStatus control exists, the user will be redirected to the login page upon clicking the Logout link.

LoginView

Of all of the new controls that ship with ASP.NET 2.0, the LoginView control provides what is probably one of the biggest savings in terms of effort and lines coded.

In past versions of ASP.NET, there was no easy way to design a page where certain users saw one piece of content while other users saw a different piece of content based on their Role membership. In addition, it was also cumbersome to render a page where logged-in users saw one view and anonymous users saw a different view. The LoginView control makes all of that easy and you can use the smart tags inside the Visual Studio 2005 editor to switch between views or use the HTML source and edit the views manually.

The LoginView control allows you to encapsulate several different views using templates and show them to the user depending on their security access and logged-in status:

  • LoggedInTemplate—This view is displayed to the user when they are logged in.
  • AnonymousTemplate—This view is shown to an anonymous user.
  • Role Groups—You can optionally render a different piece of content for the user based on their role membership. If the user is a member of one of the role groups listed, the role group template will be displayed instead of the LoggedInTemplate.

Take a look at the following code snippet, which uses some of the Roles defined earlier to render different content to different security levels:

Image

As you can see, it is extremely easy to take entire sections of your page and render different views conditionally based on security clearance, role membership, and authentication status. In the preceding sample, members of the Administrators and Validated Users roles will be given access to secure information, whereas members of the Applicants role will only receive a limited view of the page. You no longer have to create multiple panels and write code that conditionally makes some panels visible or invisible in your code-behind. It is now easy to separate the views of the page, the code is efficient and reusable, and anyone else reading your code should have no trouble figuring out what information is bound for which users.

PasswordRecovery

As we all know, users forget their passwords. One of the most annoying tasks of creating a secure ASP.NET application in version 1.1 was figuring out just how to support users who had forgotten their passwords. Often a complex series of pages needed to be created to deal with this situation, taking time and productivity away from coding the actual application and business logic.

With ASP.NET 2.0, you can simply drag the PasswordRecovery control onto a form, and that form then automatically supports password recovery. If your membership provider has been configured to require the user to answer a security question, the PasswordRecovery control will not only prompt the user for that answer, but will validate the answer. You will need to tell the PasswordRecovery control the information it needs to construct and send e-mail messages, but other than that it takes very little effort to use.

Figure 28.4 shows this control prompting the user for their security question. If the user enters the correct answer, their password will be emailed to them based on the email address stored for that user in the data source.

Figure 28.4 The PasswordRecovery control in action.

Image

ChangePassword

The ChangePassword control allows the end user to change their password. The control handles all of the work of verifying the old password, ensuring that the new password meets the password strength requirements, and storing the new password in the underlying Membership data store. Just like all the other controls in this section, the display is incredibly customizable, allowing you to specify text and icons for every major part of the control. In addition, you can choose to redirect the user to a different page if the password change was successful. To use this control, just drag it onto a form and you’re ready to go.

CreateUserWizard

The task of creating a new user is now also made extremely easy. To create a page that will create a new user, simply create an empty form and then drag a CreateUserWizard control onto it. By default, this control will prompt the user for their user name, email address, password (including confirmation), and a security question if the Membership provider is configured accordingly.

You can choose to add your own custom steps to the middle of the process, prompting the user for additional information or injecting your own code into the process. One possible use for the additional steps for this wizard is to prompt for additional information or to do things like prompt for confirmation of a EULA or privacy policy. Figures 28.5 and 28.6 show the CreateUserWizard control in action.

Figure 28.5 The CreateUserWizard first page.

Image

Figure 28.6 The CreateUserWizard displaying a custom wizard page.

Image

Advanced ASP.NET Security

This section of the chapter is about one of the more advanced topics concerning ASP.NET security: securing sensitive configuration settings. If you are looking for information on general security or general encryption, other chapters in this book are more appropriate, such as Chapter 15, “Cryptography and Data Protection.” This section deals only with advanced ASP.NET security topics.

Using Protected Configuration Settings

When you create your ASP.NET application, more often than not, the connection strings used by your data tier end up in the Web.config file. This is even more common in ASP.NET 2.0, where there is a special connectionStrings element that is part of every application configuration file, whether it is for ASP.NET or Windows Forms.

The problem with this pattern is that it leaves your valuable connection string information completely exposed. If you are using password-based authentication against the database server, the username and password of a database user are sitting in plain text in the file, along with the name and/or IP address of the database server itself. In some situations you cannot afford to have this information available for viewing, but you still want the ease of use of the .NET configuration API.

With .NET 2.0, there is now a way to encrypt sections of a configuration file using the same technique that is used to encrypt pieces of SOAP envelopes when using secure Web Services. This encryption (and associated decryption) is done with the aspnet_regiis.exe tool, which is found in the following directory:

[drive]:[windows directory]Microsoft.NETFrameworkv[version]

Using the -pe option, you can encrypt a section of a Web.config file hosted as a virtual directory in IIS. Using the -pef option, you can encrypt a section of a Web.config file in a physical directory if you are not using IIS and you’re just using Visual Studio 2005’s builtin web server to test your applications.

To start this sample, create a new Web Site called ProtectedSettings. Add a Web.config file to it and add the following <connectionStrings> element:

Image

This is a simple connection string. The problem is that if this connection string contained sensitive machine names and passwords, we would need to be able to encrypt that to prevent prying eyes from seeing it while still allowing the application to access the information.

To encrypt this section, in a file-based web application, you can enter a command similar to the one in the following code:

aspnet_regiis -pef "connectionStrings"
"d:samsc# unleashed 2005chapters28codeprotectedsettings"
-prov "RSAProtectedConfigurationProvider"

Obviously you won’t want to have the carriage returns in your command-line statement. After running this command, your new Web.config file looks like the text shown in Listing 28.1.

Listing 28.1 A Web.config File Containing an Encrypted Connectionstrings Element

Image

Image

I cut out the actual hexadecimal characters of the encrypted data and replaced them with ellipses (...) in Listing 28.1 to make it easier to read. To prove that even after the encryption process you can still read the configuration file just as before from within the ASP.NET application, create a Web Form with the following lines of code in the code-behind:

foreach (ConnectionStringSettings css in ConfigurationManager.ConnectionStrings)
{
  Response.Write(css.Name + ": " + css.ConnectionString + "<BR/>");
}

When you debug this page in Visual Studio 2005, you should see that the connection string has been completely decrypted for you and is ready to pass to your ADO.NET data provider of choice.

Keep in mind that the private key used to encrypt the data contained in the web.config file isn’t actually written inside that file. This means that if you copy the encrypted web.config from one server to another, the second server will be unable to decrypt the information. For more information on using private key encryption and how to deal with the issues that arise from sharing information among multiple servers, check out Chapter 15.

Summary

This chapter introduced you to some of the incredibly useful new features of ASP.NET that dealt with security. Security consists of basically two things: authentication and authorization. You saw how to authenticate users using the different authentication providers that ship with ASP.NET and how to work with the Membership provider. In addition, you saw how to authorize users by determining and manipulating their role membership with the Role provider. Finally, you saw how to protect sensitive information contained within the Web.config file by selectively encrypting certain sections.

You should now have a firm grasp of how to protect the information in your configuration file and how to identify and authorize users of your web application, regardless of where you are storing your user information. The next chapter will provide you with even more advanced ASP.NET techniques, including how to create your own custom providers.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.16.139.62