.NET Security
Implementing Security For Web Applications
Extend ASP.NET 2.0 to meet your needs
Digg This!
How can you take advantage of the new security features of ASP.NET 2.0, and how can you extend them for the specific needs of your Web applications?
New Security Features
If the users access your application through the Internet, Forms authentication is your natural choice for authenticating the users. Among the authentication models - Forms, Windows, and Passport - the Forms authentication needs more development effort, since you need to manage the users and roles within your application. How many times have you built the user management components from scratch for your Web applications? ASP.NET 1.x supported various authentication models and role-based security, but we still had to write code for managing users and their roles. ASP.NET 2.0 brings in the following tools and class libraries that simplify the task of implementing Forms authentication:
- Web Site Administration Tool: Helps you manage users, roles, and Web configuration data conveniently through a browser
- Membership and Roles classes: Provides a standard API for managing user accounts and roles
- Providers for Membership, Roles, and other site management tasks: Encapsulates the business logics and binds the site management data with various data sources
- Security controls: Drag and drop controls for creating login forms
The arrival of these new tools and class libraries means you can now avoid reinventing the wheel. Figure 1 shows the general approach you can follow to implement Forms authentication with ASP.NET 2.0.
Flexibility is the key ingredient of these new tools and class libraries. They not only save you hundreds of lines of code, but also give you the complete control over how you can use them within your application.
The provider design pattern allows you to create your own Membership and Role providers by extending the existing ones for implementing your application-specific business and data access logics. The security controls support templates, allowing you to modify them according to the needs of your application. A quick way to understand the power of the ASP.NET 2.0 security framework is to try the Web Site Administration Tool.
Web Site Administration Tool
With the Web Site Administration Tool (WAT) in ASP.NET 2.0, you can now manage your application configuration settings conveniently through a browser (see Figure 2).
The WAT is not just a configuration setting tool. By using WAT, you can carry out a wide range of Web site administration tasks that include:
- Setting up the data providers
- Setting up the authentication
- Creating and managing user accounts and user profiles
- Creating roles and assigning them to users
- Managing application counters
- Configuring SMTP settings
You can manage your application settings locally or remotely. You can access the tool from your browser by entering the URL of your Web application with WebAdmin.axd (for example, http://localhost/YourWebApp/WebAdmin.axd). During development, you can launch this tool from Visual Studio 2005 IDE by clicking Website -> ASP.NET Configuration menu item. When you launch the tool for the first time, it looks for an existing web.config file in your application folder. If it does not find one, the tool creates a new web.config file for you. To use the WAT, you should be one of the registered users of the Web site and should have Read and write permissions to the web.config file. The tool provides a security set-up wizard that takes you through the steps needed to configure security for your Web application. Behind the scenes, WAT invokes various providers to carry out the tasks. Providers are objects that encapsulate the logics for managing the site management data.
Understanding the ASP.NET 2.0 Provider Design Pattern
In simple terms, the provider design pattern is all about class abstraction. Figure 3 shows the ASP.NET 2.0 provider design pattern for Membership and Roles.
The provider design pattern allows you to remove the dependency of your application with specific providers. For managing users and roles, ASP.NET 2.0 provides Membership and Roles classes. When you invoke the Membership object to carry out a certain task, it calls the respective provider to handle the task. ASP.NET 2.0 has defined the standard API for providers such as MembershipProvider and RoleProvider. These are abstract classes that do not have any implementation. The concrete providers inherit from the abstract providers and they implement the data access and the business logics. Examples of concrete providers included in ASP.NET 2.0 are SqlMembershipProvider and AccessMembershipProvider. You can create additional providers according to your application needs. For example, if your data source is Oracle, you may want to define an OracleMembershipProvider by deriving from MembershipProvider. If your data source is SQL server and you need to implement extra validations, you can create a custom provider by deriving from the SqlMembershipprovider. Membership and Roles are relevant to security, but there are other data such as Membership profile, page personalization, site counters, and Web events that you may want to manage as part of your Web site administration. ASP.NET 2.0 comes with ProfileProvider, PersonalizationProvider, SiteMap-Provider, SiteCounters Provider, and WebEventProvider for handling various site management data:
Storing the Site Management Data
When you store all the site management data in a single data source, ASP.NET 2.0 creates the data schema shown in figure 4.
The ASP.NET 2.0 provider model gives you several options for storing site management data:
- You can maintain the site management data in a single data source, or sections of the data in different databases. For example, you can store the Membership data in one database and the user profile data in another database.
- You can split the Membership data of your enterprise as per your business needs and store them in different databases by configuring a separate provider for each data source. For example, you can have a separate Membership store for each branch of your company. At runtime your application can decide which provider will manage which group of users.
- You can store the site management data in the same database that stores your application's business data or in a separate database.
The AccessMembershipProvider and the SqlMembershipProvider in ASP.NET 2.0 allow binding the Membership data with MS Access and MS SQL data sources, respectively. AccessMembershipProvider is the default provider. If you wish to use SqlMembershipProvider or a custom provider, you can configure this as the default provider in the web.config file. If you use a single data source for multiple applications, ASP.NET 2.0 retains the existing schema and adds the new records for each application in the existing tables. Once the providers are in place, you can start creating the users and the roles for your Web site.
Creating and Managing User Accounts
The Membership class in the System.Web.Security namespace is the core class for managing user credentials. Membership uses the relevant provider for fetching and storing membership data in the data store (see figure 5).
Using the Membership object, the tasks you can perform include:
- Creating user accounts
- Finding users by their names or e-mail IDs
- Updating user accounts (for example updating e-mail ID, updating password question and answer)
- Deleting user accounts
- Generating passwords for the users
- Validating users
- Getting MembershipUser instance for accessing various user properties within your code
- Finding users who have currently logged in to your site
The application settings in the <Membership> section of the web.config file control the behavior of the Membership. EnablePasswordRetrieval, PasswordFormat, RequiresQuestionbAndAnswer, and requiresUniqueEmail are some of the important attributes relevant for user creation. While creating the user accounts, you have the choice to make the user account immediately active or keep the user account inactive. By default, the user account is active. If you delete a user, Membership object physically deletes the user record from the database. If you want to have more control over the user management, you need to extend the MembershipProvider to include your additional validation code.
Extending the MembershipProvider
The implementation and data ac-cess logics for the Membership are in the respective provider (for example, SqlMembershipProvider) and not in the Membership object. Therefore, you need to create your custom provider by extending the existing the MembershipProvider. You can create your custom provider by inheriting from the SqlMembershipProvider, from the AccessMembershipProvider, or directly from the MembershipProvider class. If your application uses MS Access or MS SQL Server as the membership data source, but the built-in functionality in AccessMembershipProvider or the SqlMembershipProvider is not meeting your application's needs, you need to extend either the AccessMembershipProvider or the SqlMembershipProvider. Imagine that your data source is SQL server and you wish to implement some strong password rules. In this case, you can create your custom MembershipProvider as follows:
- Create the CustomMembershipProvider class by inheriting from the SqlMembershipProvider.
- Override the relevant methods to add your custom validations. The user enters the new password during the registration or when changing the password. Therefore, to implement custom validation for the password, you need to override the CreateUser, ValidateUser, and ChangePassword methods. After including your custom validations, you can take advantage of the functionality provided by the existing provider by calling the relevant method in the base class.
- Configure your new provider for the Membership in the web.config file. You can provide any friendly name for the provider, but you need to specify the type correctly:
<membership defaultProvider="Raj1">
<providers>
<add name="Raj1" type="CustomMembershipProvider"/>
</providers>
</membership>
Listing 1 contains the sample code for the CustomMembershipProvider. If your data source is not MS SQL Server or MS Access, you have to create your CustomMembershipProvider by inheriting from the MembershipProvider class. Since the MembershipProvider class does not have any implementation code, you need to write the code for the data access and the business logic necessary for your application by overriding the methods of the MembershipProvider. If you are building several applications for an enterprise and the data access and business logics for the Membership remain the same, you can create your CustomMembershipProvider as a separate class library project and use this across many applications.
Forms Authentication - With or Without Cookies
The Forms authentication so far relied on the browsers that support cookies. ASP.NET 2.0 removes this limitation. As an ASP.NET developer, you are aware of the FormsAuthentication.RedirectFromLoginPage method. After validating the user credentials (during login), when you call this method, it creates the authentication ticket, encrypts the same and adds it to a cookie. The method then adds the cookie to the HTTP response and redirects the user to the requested page. On each subsequent page request, Application_AuthenticateRequest event is fired. The FormsAuthenticationModule handles this event. On each AuthenticateRequest event, the FormsAuthenticationModule looks for the cookie that contains the authentication ticket. If a valid authentication ticket is found, it decrypts the information and populates the Context.User. If the authentication ticket does not exist, the module the user is directed to is the login page again. You can now control how the authentication ticket is verified or stored by specifying the cookieless attribute in the authentication section of the web.config file or the machine.config file:
<authentication mode="Forms">
<Forms cookieless=" UseURI"/>
</authentication>
When you set the value to UseURI, the authentication ticket will always be stored in the URL. When you set the value of cookieless attribute to "AutoDetect," the authentication ticket will be set in a cookie, and if the attempt fails, the ticket will be stored in the URL. Other possible values for the cookieless attribute are: UseURI, UseCookies, and UseDeviceProfile. UseCookies will force the authentication ticket to be stored in the cookie. Finally, UseDeviceProfile detects whether to use cookies based on the device profile setting.
Creating and Managing Roles
ASP.NET 2.0 introduces the RoleManager feature to simplify the role management. To add roles to your application, you must enable the RoleManager in the web.config file. The following example enables roleManager and sets the sqlRoleProvider as the default role provider:
<roleManager enabled="true" defaultProvider="Raj1" domain="">
<providers>
<add name="Raj" type="System.Web.Security.SqlRoleProvider/>
</providers>
</roleManager>
ASP.NET 2.0 provides you with the System.Web.Security.Roles API for creating and managing roles (Please note the name of the class that handles the role management is "Roles" and not RoleManager). As with the Membership, the Roles object uses its provider - the RoleProvider - to bind the role information with the database (see Figure 6).
Among the tasks you can perform using the Roles object are:
- Creating roles
- Adding roles to users
- Removing roles from users
- Finding users in a given role
- Finding roles of a user
All the methods in the Roles class are static, so you need not create the Roles object instance to call any of its methods. You can manage your application roles using the Roles API, or more conveniently using WAT. If you want to add application-specific business logics in the role management, you need to create a custom role provider by extending an existing provider such as SqlRoleProvider.
Extending the RoleProvider
The implementation and data access logics are in the respective role provider (for example, SqlRoleProvider) and not in the Roles object. Therefore, you need to create your Custom Role Provider, from extending the RoleProvider, class and not the Roles class. The Roles class is not inheritable. You can create your provider by inheriting from the SqlRoleProvider, from the AccessRoleProvider, or directly from the RoleProvider class. Imagine that you are building an enterprise application with a business rule that at least two users should exist in the system with the Administrator Role. By default, Roles does not verify how many users are in a role before removing users to the role. You can create the custom Role Provider for SQL data source that implements this business rule as follows:
- Define your customRoleprovider class by inheriting from System.Web.Security.SqlRoleProvider.
- Override the methods that need to include your custom validations. To verify the number of users in a given role before removing the role from the user, you need to override the RemoveUsersFromRoles method.
- Configure your new provider in the <RoleManager> section of the web.config file:
<roleManager enabled="true" defaultProvider="Raj" domain="">
<providers>
<add type="CustomRoleProvider"/>
</providers>
</roleManager>
Listing 2 contains the sample code for the CustomRoleProvider.
Controlling Access to the Resources
As with ASP.NET 1.x, you can set up the access control at the Web site level, at folder level, or at the individual file level. To control the access, specify the roles in the <allow> or <deny> elements of the Web configuration file for the each folder or location you want to protect. If you define more than one rule for a directory, ASP.NET checks for the first matching rule and ignores the remaining rules. An easy way to manage access rules is to use WAT (see Figure 7).
You should also ensure that you have defined the access control for the WAT. The following example allows only the Administrator role to access the WAT:
<WebSiteAdministrationTool>
<authorization>
<allow roles="Administrator"/>
<deny users="o"/>
</authorization>
</ WebSiteAdministrationTool>
Sometimes, more than one role may access a page, and you may have to enable or disable specific buttons for specific roles. After the user logs in and is authenticated, you can call the Roles.IsUserInRole method to check if the user is in a role. By default, ASP.NET 2.0 caches the user roles in cookies to save the calls to the database. ASP.NET 2.0 encrypts the role names before storing them in the cookie. This is safe in most situations. If you want to avoid storing the user's roles in cookies, you can set the CacheRolesInCookie attribute to false in the <roleManager> section of the web.config file.
Using the Security Controls
ASP.NET 2.0 comes with several new controls to implement login related functionality. Among the tasks you can perform using these security controls are:
- Creating a login form that collects the user ID and password from the user and verifying the user credentials with the data available in the data source
- Implementing the password recovery feature to enable the user to recover the password
- Implementing the change password feature to enable the user to change the password
- Implementing the user self-registration feature
Creating a login form is as easy as dragging and dropping the relevant controls and setting some basic properties. With the PasswordRecovery control, you can have the user provide the user ID and optionally prompt the user to provide an answer to the security question. Upon successful validation, ASP.NET 2.0 will send the password to the user by e-mail. The ChangePassword control will enable the user to change the password by providing the current password and new password. You can use the LoginStatus control to enable the user to login or logout from any form. This control will automatically toggle between the login and the logout view based on the user's current login status. If your Web site allows users to self-register with your site, you can use CreateUserWizard control to build a user registration form. After dragging a security control onto a form, you can convert it as a template and customize them according to your application needs (see Figure 8).
The available customization choices include:
- Adding more controls such as text boxes and combo boxes in the template
- Writing additional validation code for the events exposed by the controls
- Changing the look and feel by changing the properties such as font, color, and label names
After adding new controls to a template, you need write code to handle the events for these additional controls.
Protecting the Application Configuration Settings
Unlike ASP.NET 1.x, ASP.NET 2.0 has a separate section for storing the database connection strings:
<connectionStrings>
<add name="Rajconn"
connectionString="server=MyServ;
user ID=xxx;password=yyy;database=Raj"/>
</connectionStrings>
For security reasons, you may want to store the connection string in the encrypted format. With the ProtectedConfigurationProviders in ASP.NET 2.0, you can now store sensitive sections such as <connectionStrings> in the encrypted format. There are two ProtectedConfigurationProviders shipping with ASP.NET 2.0: The RSAProtectedConfigurationProvider and the DPAPIProtectedConfigurationProvider. The RSAProtectedConfigurationProvider is suitable for Web farms since this allows you to export and import the encryption keys. You need to specify the sections you want to store in the encrpted format by adding the names of the relevant sections in the <protectedDataSections> of the web.config or machine.config file. The following setting tells ASP.NET the <connectionString> section will be in the encrypted format and the provider responsible for encryption and decryption is the RSAProtectedConfigurationProvider:
<protectedData>
<protectedDataSections>
<add name="connectionStrings" provider="RSAProtectedConfigurationProvider" />
</protectedDataSections>
</protectedData>
Once you have specified the names of the sections you intend to encrypt in the <protectedDataSections> of the configuration file, you can encrypt the relevant section using the aspnet_regiis tool. The following command will encrypt the connectionString section for the application named "MyApp":
aspnet_regiis -pe "connectionStrings" -app "/MyApp"
ASP.NET handles the decryption tasks automatically, so you can access the information in the protected sections without writing any code for decryption.
Conclusion
With ASP.NET 2.0 providing a standard security infrastructure for implementing Forms authentication, you can gain significant savings in the code you write for implementing security for your Web applications. Since the providers and controls in ASP.NET 2.0 are extensible, you have complete control while using them in your application. Creating a custom MembershipProvider or a custom RoleProvider is as simple as inheriting from an existing provider and adding few lines of code to implement your application-specific logics. Building login forms and user registration forms is now as easy as dragging and dropping the relevant security controls and setting the required properties. With the solid security framework in place, implementing security for Web applications is no longer a burden for developers!
About Rajendran SenapathiRajendran Senapathi has over 15 years' experience in architecting, designing, and developing software systems for clients in India, U.K., U.S., Australia, Austria, China, and Hong Kong. Rajendran specializes in Microsoft.NET technologies. Currently he is in U.K., providing architecture and design consultancy to bluechip clients. Rajendran holds M.S. degree in Systems & Information from the Birla Institute of Technology and Science, Pilani, India. He is an MCSD.NET Early Achiever, Prince2 Registered Practitioner, and Project Management Professional.