Encrypting connection strings in Windows Azure web applications

You may not want your connection strings embedded in your web.config in plaintext – that will expose your database credentials to all the world. This blog post shows how to secure the connection strings. It is ugly, but quite doable.

Note: SQL Azure team has posted a four-part series on this in September 2010. Some details have changed since, and this post aims at being more practical, shorter and easier to follow. I’ll also discuss the common problems with the method. But feel free to read their version as well :-)

What do I need to do?

.NET Framework supports encryption of configuration elements per configuration section. Thus, you’ll probably end up encrypting your whole connectionStrings section. This is likely to be just OK for you.

There are the following stages to the process:

image

Let’s go through these steps one by one.

Creating a certificate

You will need to create a certificate that is used as the encryption key. First you use this certificate to encrypt the configuration, then your site uses it to decrypt the configuration. To achieve your security gaols, you should make sure that the certificate and its password are safely stored. Ideally, your developers would never even see it.

Open up a Visual Studio Command Prompt (for example, a “VS2012 x64 Cross Tools Command Prompt”, “Developer Command Prompt for VS2012” or similar), and type the following. “MyApp Connection Strings” is just a name for the certificate, and the rest of MyApps are file names. There is no magic in those names.

makecert -r -pe -n "CN=MyApp Connection Strings" -sky exchange "MyApp.cer" -sv "MyApp.pvk"

You will need to type a password for the certificate (thrice). Keep it safe, because you’ll need it. Next, you’ll need to merge the .cer and .pvk files into another certificate file format .pfx. Do this with the following command line:

pvk2pfx -pvk "MyApp.pvk" -spc "MyApp.cer" -pfx "MyApp.pfx" -pi "password"

Put the password you set earlier into the argument value for the –pi switch.

Importing the certificate locally

image To be able to encrypt the configuration, you must import the certificate on a workstation. Tap Windows-R and run mmc.exe to open up the Management console. Add the Certificates snapin by using File > Add/Remove Snapin and enabling Certificates snap-in. Select the “Computer” account in the next dialog, and “Local computer” in the next one.

Once you have added the snapin, open the Personal store, right-click to open the All Tasks menu and choose Import.

image

Use the import wizard to import the certificate. By default, the file browser filters to *.cer files, which contain only public key information useful for encrypting the configuration information. The default options for the following dialogs are fine.

Under normal circumstances, you should only distribute the .cer file to people who need to encrypt the configuration. The .pfx (and .pvk) files contain the private key that can be used to decrypt the configuration – that should be kept behind locks and only installed into Azure. But for practical purposes, you may want to install the .pfx at this point so you can actually test the thing before pushing it out. If you do import the pfx, you also need to enter the password you chose earlier.

Adding the encryption provider

The pfx file represents the certificate format known as PKCS #12. To use the certificate in your application, you need to write a class that supports said encryption format and still works in Windows Azure. Microsoft actually provides one, but it comes in a Visual Studio 2008 solution. You can just get the relevant class file from here: Pkcs12ProtectedConfigurationProvider.cs.

Add the class into your solution. You can put it wherever you want, but the place must be precompiled into an assembly (i.e. an MVC project, class library, just not ASP.NET App_Code or other runtime compilation spots). You may need to add some assembly references (System.Configuration, System.Data, System.Security, System.Xml) to make it work. Change the namespace to something you want to see in your application: you will need the full type name later on.

image

Adding the certificate to your solution

In Solution Explorer, open the Roles node under your Cloud Service Project and open the Properties of your web role whose configuration you want encrypted. Choose Certificates and Add the Certificate. The default store location of “LocalMachine” and store name of “My” are good. The Name field defaults to something like “Certificate1”, but that is not important.

Click the “…” button in the Thumbprint field to select the certificate. You’ll get the dialog seen on the right.

Once you have picked the certificate, you will get a thumbprint value that is a hex string (“64DC1BB08D4E993D6D2A20BB543079F55968F4F4”). This value identifies your certificate, and in order for your next cloud publishing to succeed, a certificate with this thumbprint must already be uploaded to the Azure.

Encrypting your configuration

First, set up your configuration encryption provider by adding the following section to your web.config. Remember that if you have a configSections block, it must be the first block in the configuration file. In fact, encrypting your configuration deletes your configSections if it isn’t the first section – that’s probably a bug.

<configProtectedData>
	<providers>
		<add name="Pkcs12Provider" thumbprint="64DC1BB08D4E993D6D2A20BB543079F55968F4F4" 
                     type="MyApp.Utils.Pkcs12ProtectedConfigurationProvider, MyApp"/>
	</providers>
</configProtectedData>

Remember to replace the example’s thumbprint with your own certificate’s thumbprint you got from the previous step. If you lost it, just open the Certificate properties page for your Web Role under the Cloud Service project. Also, make sure the type attribute contains the full namespaced name of your provider and the assembly filename after the comma (i.e. “MyApp.Security” for MyApp.Security.dll).

Now it is time to actually encrypt your connection strings, which is the ugly part. The encryption is done by issuing the following command in the Visual Studio command prompt, while in the same directory as your web.config. The parameters you pass in are the name of the configuration section to be encrypted, the path of the configuration file and the name of the provider.

aspnet_regiis -pef "connectionStrings" "." -prov "Pkcs12Provider"

But don’t do it just yet. If you do, you will get an error on the lines of “Could not load file or assembly ‘MyApp’”, referring to the assembly that should contain the provider.

Note: If you run this in a directory that doesn’t have a web.config to encrypt, you’ll get an error message stating “The protection provider ‘Pkcs12Provider’ was not found. Strange error, but check your current working directory.

Aspnet_regiis will look for the specified assembly from a very limited set of lookup paths. First and foremost, it looks for the assembly in the GAC. Since it is typically cumbersome – and even bad practice – to register your application DLLs in the GAC, you shouldn’t do that.

Microsoft’s canned solution (to which I linked above) works around this by wrapping the configuration provider in a separate DLL, which is then strongly named. The solution also contains an installer project that puts the provider into the GAC. But since the installer project doesn’t build in new versions of Visual Studio, that is fairly clumsy. That said, if your organization already has a tool DLL that is typically deployed into GAC, you can include the provider in that assembly. If you do that, everything should just work (but of course, you need to refer to the assembly with its full name and all the attributes).

So, the next issue: How to make aspnet_regiis find your DLL without pushing it into GAC?

The easiest approach is to copy your DLL into the directory where aspnet_regiis.exe resides, typically C:\Windows\Microsoft.NET\Framework\v4.0.30319 or something similar. You end up putting your binaries behind .NET’s internal ones, which isn’t very nice, but it works.

If you want avoid some of that mess, put the DLLs in a separate directory as outlined in a StackOverflow answer. Unfortunately, the directory must still reside under aspnet_regiis.exe’s location. And you can go further with features such as DEVPATH, but I wouldn’t bother unless you really need to.

Once you’ve resolved the DLL question and ran aspnet_regiis successfully, your configuration file should get properly encrypted. If you did install the .pfx into your certificate store, you can now also test this by running your application: if everything works, your application most obviously can access the encrypted configuration.

In case the Pkcs12ProtectedConfigurationProvider throws an ArgumentNullException with the parameter name of keyObject when you’re accessing the configuration, you probably have not imported the private part of the key (i.e. you chose the .cer file when importing).

Note that you don’t have to modify your callsites for accessing the configuration at all: .NET Framework ConfigurationManager and other classes take care of invoking the decryptor when needed.

Uploading the certificate to Azure

The only thing left to do is to push the certificate to Windows Azure. Open the Azure Management Portal, choose your Cloud Services and get over to the Certificates tab.

image

imageClick the Upload button on the bottom of the screen to choose your certificate, choose your .pfx file and enter your password.

Note: If you upload the .cer file, Azure will accept it, but you will get the (already mentioned) ArgumentNullException for parameter keyObject when trying to access the configuration.

Once you’re done with this, publish your new package to the cloud. If everything went as planned, you should now have a working solution.

Practical tips and tricks

There are quite a few ways to manage the encryption process in real development scenarios. For most teams, it is worth encrypting only the production Database (and Azure Storage) access credentials.

The easiest way to this goal would probably be this:

  1. Designate an IT pro, lead developer or another liason who is allowed to know the production credentials.
  2. Have the trusted person install the public key (.cer file) on his computer, making him able to encrypt the credentials.
  3. Make your version-controlled web.config have the development configuration; typically plaintext is just fine here.
  4. Once the trusted person has created an encrypted connectionStrings section, put that in a config transformation file with the xdt:Transform=”Replace” approach. You will also need to use xdt:Transform=”Insert” to add the configProtectedData section.
  5. You can now freely check in the config transformation as well.
  6. As is normal with encryption keys, store the private key (.pfx) and its password carefully, preferably in separate locations.

Finally, here is an example of a transformation file that handles the described scenario.

<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
  <connectionStrings configProtectionProvider="Pkcs12Provider" xdt:Transform="Replace">
    <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#aes192-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>rsaKey</KeyName>
          </KeyInfo>
          <CipherData>
            <CipherValue>A4K8W5Hr...</CipherValue>
          </CipherData>
        </EncryptedKey>
      </KeyInfo>
      <CipherData>
        <CipherValue>G5cpXKvbY...</CipherValue>
      </CipherData>
    </EncryptedData>
  </connectionStrings>

  <configProtectedData xdt:Transform="Insert">
    <providers>
      <add name="Pkcs12Provider" thumbprint="64DC1BB08D4E993D6D2A20BB543079F55968F4F4" type="MyApp.Utils.Pkcs12ProtectedConfigurationProvider, MyApp"/>
    </providers>
  </configProtectedData>
</configuration>

Have a nice encryption!

June 12, 2013 · Jouni Heikniemi · 55 Comments
Tags: , , ,  · Posted in: .NET, Cloud, Web

55 Responses

  1. Winford Hertzel - January 12, 2021

    Please keep on dropping such quality storys as this is a rare thing to find these days. I am always searching online for posts that can help me. looking forward to another great website. Good luck to the author! all the best!

  2. max maillots - January 22, 2021

    Site Maillot Foot Pas Cher Maxmaillots Shop 2020/2021
    http://www.maxmaillots.shop/

  3. cheap psychic - February 2, 2021

    For most recent news you have to visit web and on internet
    I found this site as a most excellent site for latest updates.

  4. Rara - February 24, 2021

    Hello…

  5. swap nudes - April 26, 2021

    What i don't realize is if truth be told how
    you're now not really much more neatly-favored than you might be right now.
    You're so intelligent. You know therefore considerably on the subject of this subject, made me in my view consider it from a lot
    of varied angles. Its like men and women don't seem to be involved except
    it is something to accomplish with Girl gaga! Your own stuffs nice.
    All the time handle it up!

Leave a Reply