Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Asp Net 2.0 Security Membership And Role Management

.pdf
Скачиваний:
55
Добавлен:
17.08.2013
Размер:
12.33 Mб
Скачать

Chapter 4

Defining Protected Configuration Providers

The default protected configuration providers are defined in machine.config:

<configProtectedData defaultProvider=”RsaProtectedConfigurationProvider”> <providers>

<add name=”RsaProtectedConfigurationProvider” type=”System.Configuration.RsaProtectedConfigurationProvider, ... “ description=”Uses RsaCryptoServiceProvider to encrypt and decrypt” keyContainerName=”NetFrameworkConfigurationKey”

cspProviderName=””

useMachineContainer=”true” useOAEP=”false” />

<add name=”DataProtectionConfigurationProvider” type=”System.Configuration.DpapiProtectedConfigurationProvider,...” description=”Uses CryptProtectData and CryptUnProtectData... “ useMachineProtection=”true”

keyEntropy=”” /> </providers>

</configProtectedData>

If you author or purchase a custom provider, you would configure it in the <configProtectedData /> section and assign it a name so that tools like aspnet_regiis can make use of it. Other than the “name” and “type” attributes, all of the information you see on the provider <add /> elements is unique to each specific provider. Custom providers can support their own set of configuration properties that you can then define when you configure them with the <add /> element.

As with most other provider-based features, you can define as many protected configuration providers as you want. Then when using a tool like apnet_regiis, writing code with the ProtectSetion method, or creating web.config files, you can reference one of the protected configuration providers from <configProtectedData /> by name. For example, the -prov command-line switch you saw earlier on aspnet_regiis refers to a named provider within <configProtectedData/>. In these scenarios, if you do not explicitly select a provider, then the value of defaultProvider on the <configProtectedData /> element is used. This means that by default the RSA provider is used for protected configuration.

DpapiProtectedConfigurationProvider

This protected configuration provider uses the data protection API (DPAPI) that is part of Windows. This functionality will probably be familiar to those of you who used the aspnet_setreg tool back in ASP.NET 1.1 or who wrote a managed DPAPI wrapper for use in applications. The nice thing about the DPAPI provider is that it is very easy to use. Configuring the provider is quite simple because you need to consider only two provider-specific options:

keyEntropy — This is a string value containing some random information that will be used during the encryption process. If you use a different keyEntropy value for each application, applications that share the same set of DPAPI encryption keys still cannot read each other’s protected configuration data.

172

Configuration System Security

useMachineProtection — Because DPAPI has the concept of a machine store and a per-user store, this configuration attribute indicates which one to use. If you set this attribute to true (the default), all applications can decrypt each other’s protected configuration data. If you set this attribute to false, then only applications running under the same credentials will be able to decrypt each other’s protected configuration data.

The DPAPI provider should really be used only for single-machine applications. Although you can go through a manual step whereby you always reencrypt your configuration files after they have been deployed to a machine, this is inconvenient. Furthermore, it opens up the possibility of someone forgetting to encrypt a configuration file (and remember you may need to encrypt multiple configuration files up the configuration inheritance hierarchy).

keyEntropy

The keyEntropy option is only useful for giving a modicum of protection against two different applications reading each other’s configuration data when useMachineProtection is set to true. With the machine-wide DPAPI key store technically anyone who can get code onto the machine will be able to successfully decrypt your protected configuration data. Specifying an entropy value gives you a lightweight approach to protecting the encrypted data. You can use keyEntropy with the per-user mode of operation for DPAPI as an additional layer of protection although the per-user mode for the DPAPI provider is not suitable for use with web applications.

If each web application uses a different keyEntropy parameter in its configuration, only code with knowledge of that value will be able to read the configuration data. Of course, the management problem with using keyEntropy is that you need a separate provider definition for each different keyEntropy value. If you have a fair number of applications to protect on a server, and you want to isolate the encrypted data between each application, you can easily end up with dozens of provider definitions just so that you can use a different keyEntropy value for each application.

There is also the related issue that you need to ACL the appropriate configuration files so that random users cannot open them and read the configuration. Placing the different provider definitions in machine.config or the root web.config prevents applications running at Medium trust or lower from being able to use the strongly typed configuration classes to read the raw provider definitions (note that the actual provider class DpapiProtectedConfigurationProvider doesn’t expose the keyEntropy value as a property).

However High and Full trust applications have the ability to open any file on the file system (ACLs permitting). For these types of applications, you need to run each application in a separate application pool with each application pool being assigned a different user identity. With this approach, you can then place each application’s provider definition within the application’s web.config file, and the ACLs prevent one worker process from reading the configuration file from another application. If you were to leave the application-specific provider definition in machine.config or web.config, Full and High trust applications would be able to open these files and read the keyEntropy attribute.

Using keyEntropy is pretty basic: You just define another instance of the DPAPI provider and put any value you want as a value for this attribute:

<configProtectedData>

<providers>

<add name=”AppSpecificDPAPIProvider” type=”System.Configuration.DpapiProtectedConfigurationProvider...”

173

Chapter 4

useMachineProtection=”true” keyEntropy=”AD50GC20FKQ43%dj!@4F” />

</providers>

</configProtectedData>

You should set the keyEntropy value to something that cannot be easily guessed. In this case, I just used a random string of characters. Any long string of random values will work; there are no restrictions on the length of the keyEntropy configuration attribute. If another application attempts to decrypt a protected configuration section and uses a different entropy value, it receives an error message stating that the data in the configuration section is invalid.

useMachineProtection

The default DPAPI configuration uses the machine-wide DPAPI key store; if you configure the DPAPI provider and fail to set the useMachineProtection attribute, internally the provider will also default to using the machine-wide store. If you are running in a trusted environment and it doesn’t really matter if applications can read each other’s configuration data, this setting is reasonable.

However, if you are on a machine that hosts applications from development groups that don’t trust each other, or if you have a business requirement that different applications should not be able to read each other’s configuration data, setting useMachineProtection to false is an option. If you set this attribute to false the identity of the application needs to be switched to a different user account (see the earlier section on using per-user key stores). Of course, after you change your application to run as a different identity, you already have the option of using file ACLs as a protection mechanism for preventing other applications from reading your configuration data. In a sense, using the per-user mode of the DPAPI provider is an additional layer of protection above and beyond what you gain just by changing applications to run as different user identities.

As mentioned earlier though, there is a pretty severe limitation if you set useMachineProtection to false. Due to the way DPAPI works, it needs access to the user profile for the process identity to access the key material. On IIS6 the user profile for a worker process account (specifically machine or domain accounts other than LOCAL SERVICE or NETWORK SERVICE) is never loaded by IIS. If you follow the steps outlined in this section everything will work until you reboot the machine and the side effects of the runas command window are lost. If you really, really want to get per-user DPAPI working, you need a hack such as launching runas from a scheduled task or having an NT service that forcibly loads the profile for a user identity. Realistically though, I would never depend on such workarounds for a production application, and hence the machine store for the DPAPI protected configuration provider is the only really viable option for web applications. Non-ASP.NET applications don’t have the limitation with the Windows user profile though, so you may be interested in using DPAPI user stores for securing configuration information used by a fat client application.

To set up the provider for per-user DPAPI just change the useMachineProtection attribute to false:

<configProtectedData>

<providers>

<add name=”AppSpecificDPAPIProvider” type=”System.Configuration.DpapiProtectedConfigurationProvider...” useMachineProtection=”false”

</providers>

</configProtectedData>

174

Configuration System Security

If you use DPAPI with per-user keys you must run interactive tools like aspnet_regiis with the process credentials that will be used at runtime. The simplest way to do this is with the runas command to spawn a separate command window. Of course, this also implies that you should choose a local or domain user account for your process identity because you aren’t going to know the password for the built-in NETWORK SERVICE account.

After you spawn a command window running as the proper credentials, you can use the aspnet_regiis command to encrypt the desired configuration section. Because encrypting a configuration file requires writing a temporary file, replacing the original configuration file, and then cleaning up afterward, the identity you are running as will temporarily need Read, Write, and Modify access to the application’s directory. After the encryption operation is done, you can remove the Write and Modify privileges from the directory.

After the configuration file has been encrypted, try moving the web application into an IIS6 application pool running with the same credentials that were used to run aspnet_regiis in the spawned command window. Now when you run your web application, the encrypted sections will be transparently decrypted using the DPAPI key associated with the worker process identity. If you assign your application to a different application pool, for example the default application pool running as NETWORK SERVICE, you will see the effect of the per-user DPAPI key. Running as NETWORK SERVICE instead returns an error message that the key is not valid for the specified state, meaning that you are attempting to decrypt the data with an invalid key.

However, if you reboot your machine after the previous steps, your web application will stop working — even with everything setup properly — due to the dependence DPAPI has on the Windows user profile. As a result I wouldn’t recommend trying to get the per-user mode working for IIS6. Also be aware that if you are running IIS5 on a production machine, you can get the per-user mode of DPAPI to work because ASP.NET loads the user profile of the account specified in the <processModel /> element. However, if you move the application to an IIS6 machine, it will fail because of the lack of a loaded Windows user profile for IIS6.

RsaProtectedConfigurationProvider

As the name suggests this protected configuration provider uses the RSA public-key encryption algorithm for encrypting configuration sections. To be precise, the provider encrypts configuration sections using 3DES, but it then encrypts the symmetric 3DES key using the asymmetric RSA algorithm.

Of the two providers included in the Framework, this is definitely the preferred provider for a variety of reasons:

It works well in multimachine environments.

It supports per-user key container ACLing without any awkward dependence on user profiles.

As a result of its use of RSA, you can use other Windows cryptographic service providers for the RSA algorithm.

Because the provider internally uses the RSA classes in the framework, it is able to support exporting and importing key material. This means there is a viable approach for synchronizing key material across multiple machines in a web farm.

175

Chapter 4

The concept of securing key containers to specific users does not depend on a Windows user profile; instead it relies on having ACLs set up that grant access to specific user accounts that need to open and read key containers. As a result, using machine-wide containers with specific user ACLs is the preferred approach for isolating the encrypted configuration information for multiple applications.

Because the provider uses RSA, and internally the Framework RSA classes rely on the Windows cryptographic API (CAPI), you get the added benefit of being able to use RSA key containers other than the default software-based Microsoft implementation. Although this last point is probably relevant for a small percentage of developers, if you happen to work in a bank or in the defense industry you are probably familiar with hardware cryptographic service providers (CSPs) for CAPI. If your organization uses Active Directory as a certificate store you also may be using hardware-based CSPs. With the RsaProtectedConfigurationProvider, you have the option of configuring the protected configuration provider to use a custom CSP instead of the default software-based CSP.

The configuration options of the RSA provider are a bit more extensive than those of the DAPI provider. Aside from the standard “name,” “type,” and “description” attributes, you can configure the following:

useMachineContainer — As with the DPAPI provider you can use per-user key containers instead of machine-wide key containers. Like DPAPI, per-user key containers require a loaded Windows profile. Unlike DPAPI, machine-wide RSA key containers can be ACL’d to specific users.

keyContainerName — The RSA provider always accesses keys from a software abstraction called a key container. From a manageability and security perspective, it makes it easier to separate different applications through the use of different key containers that are locked down to specific users.

useOAEP — This option tells the providers to use Optional Asymmetric Encryption and Padding (OAEP) when encrypting and decrypting. Windows 2000 does not support this, so the default for this setting in configuration and inside of the provider is false. If you are running on Windows Server 2003 or XP, you can use this option because these operating systems support OAEP with RSA.

cspProviderName — Assuming that you have registered a custom CSP for use with CAPI, you can tell the RSA configuration provider to use it by specifying the CSP’s name with this parameter.

Of the various parameters listed here, I will only drill into the useMachineContainer and keyContainerName attributes because these settings are the ones you will most commonly worry about. For IIS6 on Windows Server 2003, you can optionally set useOAEP to true. For the cspProviderName attribute, if you already have a custom CSP configured on your web servers you will already know the string name for using it with your applications. Beyond that there isn’t anything else special that you need to do from the perspective of protected configuration.

keyContainerName

Regardless of whether you use a machine key container or a user-specific key container, the RSA protected configuration provider needs to be pointed at the appropriate container. Unlike the DPAPI provider, the RSA provider doesn’t have some central pool where keys are held. Instead, key material is always segmented into specific containers. The following default RSA provider configuration uses a default container name of NetFrameworkConfigurationKey:

<add name=”RsaProtectedConfigurationProvider” type=”System.Configuration.RsaProtectedConfigurationProvider,...” keyContainerName=”NetFrameworkConfigurationKey”

176

Configuration System Security

cspProviderName=””

useMachineContainer=”true” useOAEP=”false” />

Encrypting a configuration section with aspnet_regiis using the RSA provider looks like the following:

aspnet_regiis -pe system.web/machineKey -app /Chapter4/ConfigurationSample

In this case, the -prov option was not used, meaning the default provider for protected configuration will be used, which is the RSA-based provider. Contrasted with the output from the DPAPI provider, the output from the RSA provider is substantially more verbose:

<machineKey configProtectionProvider=”AppSpecificRSAProvider”> <EncryptedData Type=”http://www.w3.org/2001/04/xmlenc#Element”

xmlns=”http://www.w3.org/2001/04/xmlenc#”>

<EncryptionMethod Algorithm=”http://www.w3.org/2001/04/xmlenc#tripledes-cbc” /> <KeyInfo xmlns=”http://www.w3.org/2000/09/xmldsig#”>

<EncryptedKey xmlns=”http://www.w3.org/2001/04/xmlenc#”>

<EncryptionMethod Algorithm=”http://www.w3.org/2001/04/xmlenc#rsa-1_5” /> <KeyInfo xmlns=”http://www.w3.org/2000/09/xmldsig#”>

<KeyName>Rsa Key</KeyName> </KeyInfo>

<CipherData>

<CipherValue>encrypted 3DES key goes here</CipherValue> </CipherData>

</EncryptedKey>

</KeyInfo>

<CipherData>

<CipherValue>encrypted machine key section here</CipherValue> </CipherData>

</EncryptedData>

</machineKey>

The format for the RSA and DPAPI providers is based on the W3C XML Encryption Recommendation. However, the RSA provider output really needs the expressiveness of this format due to all of the information it needs to output.

There are actually two separate <CipherValue /> elements. The first <CipherValue /> element contains an encrypted version of a 3DES key. The idea behind the RSA provider is that for each configuration section that is encrypted, the provider creates a new random symmetric key for 3DES. However, you don’t want to communicate that signing key in the clear. So, the symmetric key is encrypted using an asymmetric RSA public-private key pair.

The end result of the asymmetric RSA encryption is placed within the first occurrence of the <CipherValue /> element. The only way that someone can actually decrypt the 3DES encryption key is to have the same public-private key pair in the appropriate RSA container on their system. The <EncryptionMethod /> element that ends in rsa-1_5 tells the configuration system (or more precisely the XML Encryption support in the Framework) to use the RSA algorithm to decrypt the 3DES encryption key. Internally, the protected configuration provider will hand the Framework an instance of a System.Security.Cryptography

.RSACryptoServiceProvider that has already been initialized with the appropriate RSA key container based on the configuration provider’s settings.

177

Chapter 4

The second <CipherValue /> element contains the actual results of encrypting the configuration section using 3DES. At runtime, the protected configuration provider will use the results of the RSA decryption for the 3DES key to in turn decrypt the second <CipherValue /> section into the cleartext version of a configuration section.

Although a bit counterintuitive, if you rush out and use aspnet_regiis to encrypt a configuration section with the RSA provider, when you then run your ASP.NET application, it will fail with an error stating that the RSA key container cannot be opened. This is because although the Framework ensures that an RSA container called NetFrameworkConfigurationKey is created on the machine, by default the process account for your web application does not have rights to retrieve key material from the key container.

You have to first grant read access on the key container using aspnet_regiis. For ASP.NET, you need to grant read access on the container to only the appropriate process account. Although aspnet_regiis supports granting Full access to a key container, you don’t want the identity of a web application to have rights to write to or delete containers. As a result for the default provider configuration the process account for your web application needs only Read access. The following aspnet_regiis command grants read access to the default RSA key container used by protected configuration:

aspnet_regiis -pa “NetFrameworkConfigurationKey” “NT AUTHORITY\NETWORK SER VICE”

After you do this, your web applications will be able to decrypt configuration sections using the default machine-wide container.

Now that you understand the basics of using the default key container, the next question is when would you use alternate key containers? The combination of using machine-wide containers (for example, the useMachineContainer attribute is set to true) with key containers is compelling. You can log on to a web server as local machine administrator and create a machine-wide RSA key pair in a new container using the aspnet_regiis tool. You can then selectively grant Read access on the container to certain accounts.

This means you can segment your applications into different worker processes running with different user accounts, and grant each user account Read access to a specific key container. Unlike DPAPI, just because an RSA key container is available machine-wide, it doesn’t mean that any arbitrary account can access it. The required step of granting Read access makes this approach secure and effective. It is reasonably simple to set up, and it allows you to isolate configuration data between applications. As you will see in the next section on useMachineContainer, RSA key containers that are useable machine-wide are really the only viable mechanism for providing configuration isolation to ASP.NET applications.

Creating a RSA key container can be accomplished with the following command line:

aspnet_regiis -pc “Application_A_Container”

This command creates a new RSA key container called Application_A_Container that is accessible machine-wide assuming the appropriate access control lists (ACLs) are granted. As an aside, the -pc option supports an additional -size option that allows you to specify how large you want the RSA key to be. By default, the tool will create 1024-bit keys, but the RSA standard supports keys as large as 16,384 bits if necessary.

You grant access to the newly created container using the -pa switch, as shown a little bit earlier. For this to make sense though, you must separate your applications into separate worker processes running as something other than NETWORK SERVICE. Obviously, granting key container access to NETWORK

178

Configuration System Security

SERVICE is pointless if your intent is to isolate access by worker process identity. Assuming that you use a different identity for each of your worker processes, you can use the -pa switch to grant access in such a way that each new key container is accessible by only a specific worker process account.

This approach does have a similar manageability issue to using keyEntropy with the DPAPI provider. Using a different key container per process identity means that you have to create a different RSA provider definition for each separate key container. However, you don’t have to worry about where you place the different RSA provider definitions. Even if applications are able to physically read protected configuration definitions for other applications, the key container ACLs will prevent applications running with different identities from successfully decrypting other application’s configuration sections.

useMachineContainer

As with the DPAPI provider, the RSA provider allows you to use a per-user mode of operation. The previous discussions on the RSA provider have been using key containers that are visible machine-wide. For an additional level of security, you might think that you could create key containers that are only “visible” to specific user accounts. This approach is dependent on Windows user profiles as you will see in a bit.

The first step is to define a protected configuration provider to use a user-specific key container. Something like the following:

<add name=”AppSpecificRSAProvider” type=”System.Configuration.RsaProtectedConfigurationProvider,...” keyContainerName=”UserSpecificContainer” useMachineContainer=”false” />

After you have a provider defined, the general sequence of steps enables you to use user-specific containers:

1.Open a command window running as the user account that will “own” the key container. You can log in interactively as the account or use the runas command.

2.Use the aspnet_regiis -pc -pku command to create a key container.

3.Use aspnet_regiis -pe to encrypt the desired configuration sections. You need to perform the encryption while running as the specific user account; otherwise, the configuration system isn’t going to be using the correct user-specific key container. Make sure to use the -prov option so that the tool knows to use the appropriate provider definition.

4.Log off or close the spawned command window.

5.Change the identity of your web application’s application pool to the same identity that was used to create the key container and encrypt the configuration sections.

Now when you run your web application it will be able to decrypt the encrypted configuration sections using the key pair located in the user-specific key container.

Unfortunately, this entire process suffers from the same dependency on Windows user profiles as DPAPI. If you reboot the machine, causing the user profile that was loaded in step 1 to go away, your web application can no longer decrypt the configuration section. As with DPAPI the per-user key containers are not really usable in ASP.NET applications; you need to stick with machine-wide containers and selectively ACL the RSA key containers to get configuration isolation across applications.

179

Chapter 4

Synchronizing Key Containers across Machines

The biggest advantage of the RSA provider over the DPAPI provider is that RSA provides a viable approach for synchronizing the contents of a key container across a web farm. Unlike DPAPI, RSA key pairs are exportable. The most important thing you need to do to ensure that you can synchronize keys is create your key containers so that they are exportable. The following command uses the -exp option to create a machine-wide key container with exportable keys. If you forget the “exp option the resultant key container won’t be exportable. Note that for this discussion only machine-wide key containers are used because per-user key containers aren’t really suitable for ASP.NET.

aspnet_regiis -pc ExportableContainer -size 2048 -exp

The next step is to export the key material so that it can be physically transported. The aspnet_regiis command line for export is shown here:

aspnet_regiis -pri -px ExportableContainer c:\exportedkey.xml

The -px option tells the tools that the key information in the container should be exported to the file name shown on the command line. The bold -pri option is important because it also tells the tool to ensure that the private half of the RSA key pair is exported as well. If you forget to export the private key, when you import the result on another server it will be useless because you need the private half of the key pair to be able to decrypt the 3DES encryption key from the XML in the protected configuration section.

With the export file in hand, you can go to each machine that needs to share the key material and import the key container with the following command:

aspnet_regiis -pi ExportableContainer c:\exportedkey.xml

The -pi command tells the tool to import the contents of the XML file into the specified RSA key container. After you import the file on any given machine, you should immediately delete it and wipe the directory that contained it. It would be a major security breach if the XML export file is left lying around for someone to copy and walk away with. The same holds true for the machine where the original export occurred; you should also ensure that the original export file is not lying around on disk waiting for someone to snoop.

As a last step, because this approach creates a new key container upon import, you need to use a spnet_regiis with the -pa switch on each web server to grant Read access on the key container to the appropriate worker process accounts.

At this point you have a key container called ExportableContainer on one or more machines. In a really secure web environment you can perform the encryption of your configuration sections using a system that is not directly connected to the internet. After you create a config file with all of the appropriate encrypted configuration sections, you copy the result to all of the machines in your web farm. The previous steps of importing containers and ACLing the containers are one-time setup tasks. After they have been accomplished, you only need to copy encrypted configuration files to all of your web servers.

This is a much cleaner approach than using DPAPI, where you would need to perform in-place encryption on each of your production web servers. In-place encryption is not only error-prone, but it also means the web server administrator always gets to see the before image of the configuration data. With the RSA provider, you can go so far as having a security group responsible for encrypting your production configuration files; the security group members could be the only ones that know sensitive information such as connection string passwords. Then when the security group is done with the encryption process they could hand the results back to your development team for deployment onto a production farm. In this way, only a small set of individuals actually knows the sensitive pieces of cleartext configuration information.

180

Configuration System Security

Aspnet_regiis Options

Several different command-line options have been thrown around for aspnet_regiis. The following table briefly summarizes the main options that have been used for the various samples. Each of these options usually has additional suboptions for things like per-user RSA containers, more specific virtual path information, and so on. However, the table shows only the most common options that you are likely to need:

Command line option

Description

 

 

-pc Container_Name -exp -size 4096

Creates a new RSA key container that is available

 

to any account assuming Read access is granted.

 

If you plan to export the key container you need to

 

include the -exp option.

 

The -size option lets you specify the size of the

 

RSA key that will be created in the container.

-pa Container_Name “DOMAIN\user”

Grants Read access on an RSA key container to the

 

specified user account

-pri -px Container_Name file name

Exports an RSA key container to the specified file.

 

The export file includes the private RSA key infor-

 

mation as well.

-pi Container_Name file name

Imports an RSA key container

-pe config_section_path -app /

Encrypts the configuration section identified by the

app_path -prov provider_name

configuration section path — this path looks some-

 

thing like system.web/membership.

 

The application path specified by -app denotes a

 

virtual path within the default web site unless you

 

specify a site with the -site option.

 

The encryption uses the provider specified by -

 

prov. This provider must have been defined in the

 

<configProtectedData /> section. If you want

 

to use the default protected configuration provider,

 

then -prov”is not necessary.

-pd config_section_path -app /

Decrypts the configuration section identified by

app_path

the configuration section path — this path looks

 

something like system.web/membership.

 

The application path specified by “-app denotes a

 

virtual path within the default web site unless you

 

specify a site with the “-site” option.

 

 

181