Web applications often need to store security-sensitive data, such as database connection strings and service account credentials in application configuration files. For security reasons, this type of information should never is stored in plain text and should always be encrypted prior to storage.
This How To describes how to use Data Protection API (DPAPI) from an ASP.NET application with Enterprise Services.
PAPI can work with either the machine store or user store (which requires a loaded user profile). DPAPI defaults to the user store, although you can specify that the machine store be used by passing the CRYPTPROTECT_LOCAL_MACHINE flag to the DPAPI functions.
The user profile approach (adopted by this How To) affords an additional layer of security because it limits who can access the secret. Only the user who encrypts the data can decrypt the data. However, use of the user profile requires additional development effort when DPAPI is used from an ASP.NET Web application because you need to take explicit steps to load and unload a user profile (ASP.NET does not automatically load a user profile).
For a related article that shows how to use DPAPI with the machine store (directly) from an ASP.NET Web application (without requiring an Enterprise Services application), see “How To: Use DPAPI (Machine Store) from ASP.NET” within the Reference section of this book.
The approach described in this How To uses a .NET serviced component running in an Enterprise Services (COM+) server application to perform the DPAPI processing for the reasons outlined in the following section, “Why Use Enterprise Services?” It also uses a Windows service for the reasons in the “Why use a Windows Service?” section. The solution configuration is shown in Figure 1 on the next page.
In Figure1, the sequence of events is as follows:
The Windows service control manager starts the Win32 service and automatically loads the user profile associated with the account under which the service runs. The same Windows account is used to run the Enterprise Services application.
The Win32 service calls a launch method on the serviced component, which starts the Enterprise Services application and loads the serviced component.
The Web application retrieves the encrypted string from the Web.config file.
The application calls a method on the serviced component to decrypt the connection string.
The serviced component interacts with DPAPI using P/Invoke to call the Win32 DPAPI functions.
The decrypted string is returned to the Web application.
DPAPI requires a Windows account password in order to derive an encryption key. The account that DPAPI uses is obtained either from the current thread token (if the thread that calls DPAPI is currently impersonating), or the process token. Furthermore, using DPAPI with the user store requires that the user profile associated with the account is loaded. This presents the following issues for an ASP.NET Web application that wants to use DPAPI with the user store:
Calls to DPAPI from an ASP.NET application running under the default ASPNET account will fail. This is because the ASPNET account does not have a loaded user profile.
If an ASP.NET Web application is configured to impersonate its callers, the ASP.NET application thread has an associated thread impersonation token. The logon session associated with this impersonation token is a network logon session (used on the server to represent the caller). Network logon sessions do not result in user profiles being loaded and it would also not be possible to derive an encryption key from the password because the server does not have the impersonated user’s password (unless the application uses Basic authentication).
To overcome these limitations, you can use a serviced component within an Enterprise Services server application (with a fixed process identity) to provide encryption and decryption services using DPAPI.
A Windows service is used in this solution in order to ensure that a user profile is automatically loaded. When the Windows Service Control Manager (SCM) starts a service, the SCM also loads the profile of the account the service is configured to run as.
The service is then used to load the serviced component, which causes the Enterprise Services server application (in an instance of Dllhost.exe) to start.
Due to the fact that the Windows service and the serviced component are configured to both run using the same least privileged account, the serviced component has access to the loaded user profile and as a result can call DPAPI functions to encrypt and decrypt data.
If the service component is not launched from a Windows service (and the service is taken out of the picture) the user profile will not automatically be loaded. While there is a Win32 API that can be called to load a user profile (LoadUserProfile), it requires the calling code to be part of the Administrators group, which would defeat the principle of running with least privilege.
The service must be running whenever the Encrypt and Decrypt methods of the serviced component are called. When Windows services are stopped, the configured profile is automatically unloaded. At this point, the DPAPI methods within the serviced component would cease to work.