ASP.NET 2.0 Security Practices - Sensitive Data

From Guidance Share

Jump to: navigation, search


How to protect sensitive data in a database

If you need to protect data in a database that is accessed by multiple Web servers, you need to encrypt the data with a strong symmetric encryption algorithm and protect the encryption key with DPAPI.

To encrypt sensitive data in a database accessed by multiple servers in a Web farm:

  • Use a strong symmetric encryption algorithm such as 3DES or AES.
  • Use the System.Security.Cryptography.RNGCryptoServiceProvider class to generate a strong (192 bit, 24 byte) encryption key. Back up the encryption key, and store the backup in a physically secure location.
    Note Cryptographically, 3 DES keys are effectively 168 bits in length rather than 192 bits. This is because in each of the three DES applications, a 56 bit key is used even though the block size is 64. The remainder of the 8 bits were meant to be parity bits but were never really used for that purpose. 3DES therefore, uses three times 56 or 168 bit keys.
  • Use DPAPI to encrypt the symmetric encryption key on each Web server and store it in a secured registry key. Create an ACL to protect the registry key that allows full control for administrators and read only access for your ASP.NET process account.

To encrypt data and decrypt data, retrieve the encrypted symmetric encryption key from the registry, use DPAPI to decrypt the key and then use the System.Security.Cryptography.TripleDESCryptoServiceProvider class with the encryption key to either encrypt or decrypt the data stored in the database.

With this process, if the DPAPI account used to encrypt the encryption key is damaged, the backup of the 3DES key can be retrieved from the backup location and be encrypted using DPAPI under a new account. The new encrypted key can be stored in the registry and the data in the database can still be decrypted.

How to encrypt configuration data in a Web farm

To encrypt configuration data in a Web farm, use RSA encryption with a machine-level key container because you can easily export RSA keys. You need to do this if you encrypt data in a Web.config file prior to deploying it to other servers in a Web farm. In this case, the private key required to decrypt the data must be exported and deployed to the other servers.

In the following approach, you create and export a custom RSA encryption key. Then you install it on the target servers and secure it with an ACL that permits access only to your application's identity.

To use RSA to encrypt data in a Web farm:

  1. Run the following command from a command prompt to create an exportable custom RSA encryption key:
    aspnet_regiis -pc "CustomKeys"–exp
    You can verify that a custom key container exists by looking for the file and checking timestamps in the following location:
    \Documents and Settings\All Users\Application Data\Microsoft\Crypto\RSA\MachineKeys
  2. Add and configure a custom protected configuration provider by adding a <configProtectedData> section to your Web.config file. Note that the key container name is set to "CustomKeys" which is the name of the key container created previously.
        <add keyContainerName="CustomKeys" 
                 description="Uses RsaCryptoServiceProvider to encrypt and decrypt"
                     Version=, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
  3. Run the following command from a command prompt to encrypt the connectionStrings section using the custom RSA key:
    aspnet_regiis -pe "connectionStrings" -app "/WebFarmRSA " -prov "CustomProvider"
  4. Run the following command from a command prompt to export the custom RSA encryption key:
    aspnet_regiis -px "CustomKeys" "C:\CustomKeys.xml" -pri
    The -pri switch causes the private and public key to be exported. This enables both encryption and decryption. Without the –pri switch, you would only be able to encrypt data with the exported key.
  5. Deploy the application and the encrypted Web.config file to a different server computer. Also copy the CustomKeys.xml file to a local directory on the other server, for example to the C:\ directory.
  6. On the destination server, run the following command from a command prompt to import the custom RSA encryption keys:
    aspnet_regiis -pi "CustomKeys" "C:\CustomKeys.xml"
  7. Grant access to the key container to your ASP.NET application identity. The following command grants access to the CustomKeys store to the Network Service account:
    aspnet_regiis -pa "CustomKeys" "NT Authority\Network Service"

For more information on using RSA to encrypt data in a Web farm, see How To: Encrypt Configuration Sections in ASP.NET 2.0 Using RSA.

How to protect ViewState

ViewState sent between browser and server is subject to tampering and eavesdropping threats. To detect tampering, ensure that ViewState is integrity checked with HMACs. This is the default setting.

Avoid storing sensitive data in ViewState. If you must store sensitive data in ViewState, encrypt it. A common example is the DataKeyNames property of the GridView/DetailsView/FormView controls, which retains the values of the primary key fields of a data store in ViewState. Under some circumstances, these values could be sensitive, such as an employee ID. In this case, encrypt the ViewState.

To encrypt ViewState:

  • A control on a page needs can explicitly request ViewState encryption by calling the RegisterRequiresViewStateEncryption method.
  • Alternatively, set the viewStateEncryptionMode attribute to Always.
  • Alternatively, set the viewStateEncryptionMode attribute to Always in the the <pages> element of the Web.config file or you can use an equivalent viewStateEncryptionMode attribute on the @Page directive.

If you use ViewState HMACs or encryption, and you deploy your application in a Web farm, you must ensure that the configuration files on each server share hashing and encryption keys. For more information, see How to configure the machine key in Web farms in the Configuration topic.

How to protect password

You should store passwords in a non-reversible hashed format. Generate the hash from a combination of the password and a random salt value. Use an algorithm such as SHA256. The salt value helps to slow an attacker perform a dictionary attack should your credential store be compromised, giving you additional time to detect and react to the compromise.

To store password hashes:

  1. Generate a random salt value by using the following code.
    byte[] salt = new byte[32];
  2. Append the salt to the password.
    // Convert the plain string password into bytes
    byte[] plainTextBytes = System.Text UnicodeEncoding.Unicode.GetBytes(plainText);
    // Append salt to password before hashing
    byte[] combinedBytes = new byte[plainTextBytes.Length + salt.Length];
    System.Buffer.BlockCopy(plainTextBytes, 0, combinedBytes, 0, plainTextBytes.Length);
    System.Buffer.BlockCopy(salt, 0, combinedBytes, plainTextBytes.Length, salt.Length);
  3. Hash the combined password and salt by using the following code.
    // Create hash for the password+salt
    System.Security.Cryptography.HashAlgorithm hashAlgo = new System.Security.Cryptography.SHA256Managed();
    byte[] hash = hashAlgo.ComputeHash(combinedBytes);
  4. Append the salt to the resultant hash.
    // Append the salt to the hash 
    byte[] hashPlusSalt = new byte[hash.Length + salt.Length];
    System.Buffer.BlockCopy(hash, 0, hashPlusSalt, 0, hash.Length);
    System.Buffer.BlockCopy(salt, 0, hashPlusSalt, hash.Length, salt.Length);
  5. Store the result in your user store database.

This approach means you do not need to store the salt separately. To verify a password, you extract the salt from the stored combination of the hash and salt value and then recomputed the hash using the salt value and the plaintext password value obtained from the user.

Personal tools