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 · 19 Comments
Tags: , , ,  · Posted in: .NET, Cloud, Web

19 Responses

  1. stk - June 17, 2013

    hello,
    is this also possible for web sites on azure?
    it seems to me that the custom provider together with a certificate can only be used for web roles.
    if so is there any other way to avoid plain text connections strings in web.config?

  2. Jouni Heikniemi - June 18, 2013

    Hi,

    I agree with your understanding: there is no way to upload custom encryption certificates into Web Sites. I don't think there is a particular reason why this couldn't be done on Reserved instances, but it's more complicated with Shared ones.

    With Web sites you can, however, store the connection string in the portal (see http://blog.davidebbo.com/2012/09/managing-database-connections-in-azure.html). That won't be the same as encryption, but you won't need to store the connection string in the web.config visible to the developers and stored in version control.

  3. stk - June 19, 2013

    Hello,

    Thank you for the quick reply.
    My concern is not that developers can see the connection string but in case someone gains access to the portal or web.config he can read it as it is clear text.
    i posted my question here:

    http://stackoverflow.com/questions/17189441/web-config-encryption-for-web-sites

    http://social.msdn.microsoft.com/Forums/windowsazure/de-DE/4e64bf5e-5125-4a03-9be9-5b41ba61b3de/webconfig-encryption-for-web-sites

  4. KarlB - June 26, 2013

    Concerning the part of the article about the configSections going missing if declared AFTER configProtectedData – I will agree that seems to be a bug.

    It makes no sense while the configSections element would be deleted. Oddly enough, you can successfully encrypt a custom section group if you put configProtectedData at the very top, but then you end up with missing configSections.

  5. Teddy G. - October 29, 2013

    For some reason my cert is failing to decrypt the encrypted connectionString section in the web.config when deployed to Azure. The thumbnails match and I've been able to get my local instance working so I know the cert & PKCS12 provider aren't the issue. To get decryption working locally I had to change the App Pool Identity to LocalSystem. I've tried the same with Web Role but it doesn't seem to take.

    Should I have to change the App Pool Identity for the Web Role to have access to the cert(.pfx) I uploaded to the Cloud Service?

  6. Teddy G. - October 30, 2013

    After a bit more digging I found the PKCS12 dll wasn't being deployed with the package because of some strange 'copy local' bug in VS. Toggling the property fixed the issue.

    I also found that the default App Pool Identity for a Web Role is Network Service and that this account is already granted permissions to use the cert(.pfx) that gets uploaded to the Cloud Service. You can grant permissions to the AppPool account (e.g. 'IIS AppPool\DefaultAppPool') on your dev machine through MS Management Console by right-clicking the certificate > All Tasks > Manage Private Keys…

  7. aspnet_regiis “Could not load file or assembly ‘SimpleAuthentication.Core’ or one of its dependencies.” | Blog of Colin Angus Mackay - July 12, 2014

    […] was recently following Jouni Heiknieme’s blog post on Encrypting connection strings in Windows Azure web applications when I stumbled across a […]

  8. Dermaclinics Professional Anti Aging Serum - May 19, 2016

    It's really a nice and useful piece of info. I am happy that you simply shared
    this helpful info with us. Please keep us up to date like this.
    Thanks for sharing.

  9. Hungry Shark World Apk - June 1, 2016

    Everyone on our crew was really skeptical regarding this because
    it's no straightforward factor to create a hack that's undetectable for
    the builders.

  10. link m88 - June 1, 2016

    It's going to be finish of mine day, except before end I am reading this enormous paragraph to improve my experience.

  11. hemstädning stockholm - June 2, 2016

    At first, I thought trying to brand my company this way wouldn't work, however, when I heard people humming my slogan in grocery stores, I knew I had
    a hit. Moreover, they change up some of the equipment for every
    new cleaning job. If the customers find any fault in the work, they
    must report within twenty-four hours after the repairs.

  12. billig fönsterputs - June 2, 2016

    Household Essentials is a company with a very long track record in the
    laundry product industry and it's staff has a combined over 200
    years experience in the field. There are many products out there, but my personal preference is any mild liquid
    dish detergent. There are others who have absolutely no problem with
    that — and who can actually go for months or even years, without ever thinking about the cleanliness or otherwise
    of their kitchen curtains.

  13. hot milf free tube - June 2, 2016

    You will no longer be just a hot mom, but a smokin' hot mom, because you showed him there's more to you than just a pretty face.

    The skit aired during the show last night amid much Jon & Kate Plus
    8 drama (err. We've all been accustomed to seeing
    the old fart with the drop dead bombshell that is 20+ years younger.

  14. clash royale cheat - June 4, 2016

    Attractive component to content. I simply stumbled upon your weblog
    and in accession capital to assert that I acquire actually loved account your
    blog posts. Any way I'll be subscribing on your augment and even I fulfillment you get entry to constantly quickly.

  15. Maillot Paris FR - August 2, 2016

    First off I want to say awesome blog! I had a quick question which I'd
    like to ask if you do not mind. I was interested to find out how you center yourself and clear your thoughts
    prior to writing. I've had trouble clearing my mind in getting my ideas out.
    I do enjoy writing however it just seems like the first
    10 to 15 minutes are generally lost simply just trying to figure out how to begin. Any suggestions or hints?
    Thanks!

  16. crgems - August 11, 2016

    This article is actually a nice one it assists new internet users, who are wishing
    for blogging.

  17. Margaret - August 17, 2016

    I have previously been convicted of mainly dangerous check fees,
    a misdeamor for weed possesion (they discovered 3 roaches
    in my automotive), and the massive one was i did a 12 months in fla.

  18. ptfe coating - August 24, 2016

    Large switching distances up to a hundred and seventy mm and sensors proof against rolling oils
    produced from PTFE , PP or PEEK are also accessible for the food industry.

  19. www.antondanielsson.se - August 25, 2016

    A sheet requiring to be skived from a big billet would wish about 5
    days end-to-end, as moulding would take 3-four hours, the dwell time could be about 24 hours
    and sintering would take over 2 days.

Leave a Reply