How secure is your website? How would you feel if you discovered that sensitive data had been compromised from your website? How would your customers/stakeholders feel if they knew that there was a security breach and the perpetrators were able to get a copy of your database? I know I would be devastated and unfortunately, these days no one is immune to cyber attacks. However there is a lot we can do as developers to protect our data and it is our responsibility to find the right tools for the job.
If you're developing a standard website that you know will be deployed on a server that you manage and control then there are many tools and flexibility when it comes to securing your data. You can use any number of encryption libraries and key management applications to provide cryptographic services to your site. They are built into the framework and you just need to follow best practices when it comes to securing your encryption keys.
But how can you secure a site running on Microsoft Azure?
Azure Websites allow developers to quickly deploy any site to the cloud and run it on an abstracted infrastructure.
Typical Cryptographic options for an ASP.NET website
A basic cryptographic service uses some kind of symmetric or asymmetric encryption algorithm with a set of keys to encrypt and decrypt data. You encrypt the data on the way in (storing to the database) and you decrypt your data on the way out (display on a webpage). One of the weak links in any cryptographic system is the encryption key management. Sure, there are third-party tools/services that can manage your keys for you, but let's assume we want to keep costs down (even better, free) and manage the keys yourselves. So what are your options when it comes to storing your encryption keys?
- You could store it on the local file system but this is wrong in so many ways and even worse on a shared hosting environment.
- You could embed them in the code but again with modern reverse engineering tools it would be a moot point if the server was to be compromised and your source code fell in the hands of a semi-competent developer/hacker.
- You could use the Data Protection API (DPAPI) Protect()/Unprotect() library to encrypt and store your keys in the registry, but since you cannot access the IIS User account and don't have access to the registry, this is not a viable option.
Getting Started
There are a couple of things you need before getting down to encrypting/decrypting data. First you need to get yourself an SSL certificate. However, I assume that if you are serious about security, you already use SSL in your web app anyway. If you don't already have an SSL in place, you can:
- Get a free one (GoDaddy offers a free SSL with every domain registration).
- Buy one from a third-party supplier.
- Create your own, self-signed certificate.
Whichever the case, you need to ensure that the SSL certificate comes with a private key!
Any of the preceding options is acceptable since the certificate's private key will only be used to protect your symmetric key that will subsequently be used to encrypt/decrypt your sensitive data (double encryption, I like it!). If you are a bit unsure about how encryption works or you want to brush up on the details, have a look at this excellent article by Microsoft UK Cloud Technical Evangelist Steve. Plank: Understanding encryption, public/private key, signatures and certificates.
You also need a Storage Account in Azure. Again, if you are running an Azure Website, then it's highly likely that you already have one. If not, use the Azure Portal to create one because you'll need it further down for the configuration.
Go on, I'll wait...
Back? Good. So, now that we have met all the prerequisites, let's go and install Azure.Security. Within Visual Studio, open the NuGet console and run the following:
Or you can use the Nuget Package Manager to get the same result :).
This will add the Azure.Security.dll, the Azure.Storage NuGet package and a couple of properties in your web.config. The first two are self-explanatory. The web.config properties are important since they define the parameters for the EncryptionHelper class. The properties in question are:
- StorageConnectionString: The URL to your storage account; get it from the Azure Portal.
- CertificateValue: The private key word for your SSL Certificate, for example "thisisaverylongandsecuritystringusedasmysslprivatekey123456789".
- CertificateTable: The table that will store your encrypted AES keys, for example "encryptionkeytable".
- CertificateName: The name of your certificate file, for example "mycertificate.pfx".
You have two choices when it comes to setting the values for the web.config parameters and they both come with their own pros and cons:
- Add the parameter values directly in the web.config. The pros are it is easy to manage and find. The cons are that in the case of unauthorized access, there is nothing stopping the perpetrators from accessing the sensitive information.
- Add the parameter values in the Azure portal. As long as the parameter names match, Azure will happily replace values in the web.config with the ones defined in the portal. Pros: you can leave the web.config values empty and rely on Azure to do the hard work for you. This adds another layer of security since the sensitive information is not held anywhere in the local files. Cons: you need to set the parameters in the Azure portal.
The following are the instructions for how to set this up:
- Log on to the Azure Portal.
- Go to Websites and select your website.
- Go to the Configuration tab.
- Scroll down to the App Settings section.
- Set the values as in the image below:
Note: You don't need to use option 2, but I highly recommend it, since it definitely improves the security of your system.
Place your .pfx certificate within your web project, either in the App_Data folder or any other location you feel comfortable with. The EncryptionHelper needs the path to the certificate so ensure that you can easily retrieve it in code, hence the reason I suggested the App_Data folder.
At the end of all this, your solution should look like this:
And your web.config like this:
Using Azure.Security to secure data
With the hard part behind us, we can now encrypt/decrypt sensitive information. The EncryptionHelper is the wrapper that we will use for all operations and it implements a simple interface:
- Void CreateNewCryptoKeyIfNotExists()
- Byte[] EncryptBytes(byte[] bytesToEncrypt()
- Byte[] DecryptBytes(byte[] bytesToDecryptString()
- EncryptAndBase64(string valueToEncrypt)
- String DecryptFromBase64(string valueToDecrypt)
In your Application_Start(), instantiate the EncryptionHelper and call the CreateNewCryptoKeyIfNotExists() as in the example below:
- protected void Application_Start()
- {
-
- var certificatePath = Server.MapPath("~/App_Data");
- var encryptionHelper = new EncryptionHelper(certificatePath);
- encryptionHelper.CreateNewCryptoKeyIfNotExists();
- }
This will only run once and will create the private key that will be used for encrypting & decrypting the data. Then in your code you can instantiate the EncryptionHelper and call either the encrypt/decrypt methods as you need them. A short example is provided below:
-
- var certificatePath = Server.MapPath("~/App_Data");
- var encryptionHelper = new EncryptionHelper(certificatePath);
-
-
- var encryptedString = encryptionHelper.EncryptAndBase64("test string");
-
-
- var decryptedString = encryptionHelper.DecryptFromBase64(encryptedString);
Note: Do not use the EncryptionHelper to secure user words! words should be one-way hashed and not encrypted. If you need an implementation example of word hashing you can have a look at
BCrypt or
PBKDF2.
Overall Benefits
With Azure.Security you get a cryptographic solution that will scale along with your website. Finally, this is an Open Source project so I welcome you to fork it and change it to better meet your needs.
Note: this article was originally featured on the
Microsoft Developer blog.
Resources