Tags:
Guest Editor: Today's post is from Taras Kholopkin. Taras is a Solutions Architect at SoftServe. In this post, Taras will review secure data storage in the ASP.NET MVC framework.
Secure Logging
The system should not log any sensitive data (e.g. PCI, PHI, PII) into unprotected log storage. Let's look at an example from a healthcare application. The following snippet shows when the application was not able to successfully store the updates to a particular patient. In this case, the logger is writing the patient's name and other PHI information to an unprotected log file.
log.Info("Save failed for user: " + user.SSN + "," + user.Prescription);
Instead, the application can write the surrogate key (i.e. ID of the patient's record) to the log file, which can be used to lookup the patient's information.
log.Info("Save failed for user: " + user.Identifer);
Secure Password Storage
Passwords must be salted and hashed for storage. For additional protection, it is recommended that an adaptive hashing algorithm is used to provide a number of iterations or a "work factor" to slow down the computation. If the password hashes are somehow exposed to public, adaptive hashing algorithms slow down password cracking attacks because they require many more computations. By default, the ASP.NET Identity framework uses the Crypto class shown below to hash its passwords. Notice it uses PBKDF2 with the HMAC-SHA1 algorithm, a 128-bit salt, and 1,000 iterations to produce a 256-bit password hash.
internal static class Crypto { private const int PBKDF2IterCount = 1000; // default for Rfc2898DeriveBytes private const int PBKDF2SubkeyLength = 256/8; // 256 bits private const int SaltSize = 128/8; // 128 bits public static string HashPassword(string password) { byte[] salt; byte[] subkey; using (var deriveBytes = new Rfc2898DeriveBytes(password, SaltSize, PBKDF2IterCount)) { salt = deriveBytes.Salt; subkey = deriveBytes.GetBytes(PBKDF2SubkeyLength); } ... } }
Secure Application Configuration
System credentials providing access to data storage areas should be accessible to authorized personnel only. All connection strings, system accounts, and encryption keys in the configuration files must be encrypted. Luckily, ASP.NET provides an easy way to protect configuration settings using the aspnet_regiis.exe utility. The following example shows the connection strings section of a configuration file with cleartext system passwords:
<connectionStrings> <add name="sqlDb" sqlconnectionstring="data source=10.100.1.1;userid=username; password=$secretvalue!"> </add>
After deploying the file, run the following command on the web server to encrypt the connection strings section of the file using Microsoft Data Protection API (DPAPI) machine key from the Windows installation:
aspnet_regiis.exe —pef "connectionStrings" . —prov "DataProtectionConfigurationProvider"
After the command completes, you will see the following snippet in the connection strings section.
<connectionStrings configProtectionProvider="DataProtectionConfigurationProvider"> <cipherdata> <ciphervalue>OpWQgQbq2wBZEGYAeV8WF82yz6q5WNFIj3rcuQ8gT0MP97aO9S...</ciphervalue> </cipherdata>
The best part about this solution is that you don't need to change any source code to read the original connection string value. The framework automatically decrypts the connection strings section on application start, and places the values in memory for the application to read.
To learn more about securing your .NET applications, sign up for DEV544: Secure Coding in .NET!
References
https://aspnetidentity.codeplex.com/SourceControl/latest#src/Microsoft.AspNet.Identity.Core/Crypto.cs
Taras Kholopkin is a Solutions Architect at SoftServe, and a frequent contributor to the SoftServe United blog. Taras has worked more than nine years in the industry, including extensive experience within the US IT Market. He is responsible for software architectural design and development of Enterprise and SaaS Solutions (including Healthcare Solutions).