As data breaches happen more and more these days, it’s critical to make applications as secure as possible. One of the main areas where security holes can be found is in the web.config file. By gaining access to this file, which is usually stored in clear text, an attacker can then easily gain access to databases and a host of other resources, both internal and external.
It wasn’t always like that. When .NET was still very young, most applications ran within a single Windows domain. Typically, web.config didn’t need to store passwords; database access rights were granted directly to the user account under which the application was running.
For current applications, this is no longer an option. In today’s world of distributed systems, databases and other resources often operate outside of the Windows domain and may even be controlled by different companies. Under such conditions, the correct storage of passwords, application tokens, and other system-level identifiers is very important.
The technique presented here is not new; Jouni Heikniemi (Jouni Heikniemi) talked about it back in 2013, as did the SQL Azure team three years before. But over the years, some of the steps have stopped working due to outdated tools and changing user interfaces. However, the original concept is still relevant.
Before we get into specific methods, it’s important to understand that encrypting the web.config file is only one step in the overall process of securing an application. It is important to be very clear about what it protects and what does not.
For the web.config file to be of any use, the application must be able to decrypt it. If you store the decryption key in a file near the web.config file, it is obvious that an attacker will simply gain access to this in addition to the web.config file. Embedding the decryption key in the application makes it a little more difficult for an attacker, but this can be dealt with simply by running a decompiler on the stolen code of your application.
Digital certificates are different. They are stored at the OS level, so attackers can’t just fish them out of the hard drive. Unless you explicitly allow it, they can’t even be exported from the computer they’re on.
It cannot be said that this is the ideal solution. If an attacker can write to the application’s directory, the application can be modified to decrypt and expose the contents of web.config. This means that you must take care to protect the directories containing the application code from being written to. Ideally, only your build server can write to your application directories on the production server, but that is beyond the scope of this article.
Another issue is the protection of copies of the digital certificate itself. They are needed to set up new servers, but in all other cases, they should be stored in some offline storage or other safe place. On the other hand, you can still share digital certificates, but only in this case there is an extreme need.
Create a digital certificate
Digital certificates consist of a public and private key. They are similar to SSL/TLS certificates, but are self-signed because they do not need to verify who created the encrypted file. Windows developers used to use makecert.exe in the past, but this tool is now obsolete. (It can still be found in the Windows SDK.)
These days, PowerShell is considered the right tool for generating certificates on Windows computers. To create a certificate, use the following commands:
WARNING: You may need to run PowerShell commands as an administrator.
$cert = New-SelfSignedCertificate -Type DocumentEncryptionCert -Subject "CN=DevConfig" -KeyExportPolicy Exportable -KeySpec KeyExchange Export-Certificate -Cert $cert -FilePath ".\DevConfig.cer" $mypwd = ConvertTo-SecureString -String "1234" -Force -AsPlainText Export-PfxCertificate -Cert $cert -FilePath ".\DevConfig.pfx" -Password $mypwd $cert
As you might guess from its name, the team New-SelfSignedCertificate creates a certificate. In this example it’s called “DevConfig”, but you can name it whatever you want.
We then export the encryption certificate to a “.cer” file using the command export-certificate. This is the public key used to create encrypted configuration files.
The next two lines allow us to export the decryption certificate as a “.pfx” file using Export-PfxCertificate. It is extremely important that this file is stored in a secure offline location separate from the password you defined with ConvertTo-SecureString. (And, of course, you should replace “1234” with a more secure password.)
For the next steps, you will need to know the thumbprint of the certificate. The last line, “$cert”, will itself display the thumbprint on the screen. Thumbprint is no longer considered a secret.
Importing an Encryption Certificate to Windows
If you are setting up a machine that can encrypt but not decrypt configuration files, then this step will be helpful. Otherwise, skip straight to the next one.
Import-Certificate -Filepath ".\DevConfig.cer" -CertStoreLocation cert:\LocalMachine\My
In chapter Import-Certificate you will find more information.
Import a decryption certificate in Windows
This step will actually import both the decryption certificate and the encryption certificate (also known as the public and private keys).
$mypwd = ConvertTo-SecureString -String "1234" -Force -AsPlainText Import-PfxCertificate -FilePath ".\DevConfig.pfx" -CertStoreLocation Cert:\LocalMachine\My -Password $mypwd
If you are importing the certificate with Import-PfxCertificate, it is not exported by default. This means that no one else will be able to export it from this machine to another. Although it is generally desirable for production to do so, you can mark it as exportable for development machines.
you can use certificate management toolto make sure the certificate was installed correctly.
Import decryption certificate to Windows Azure
The decryption certificate is not available in the free version of Azure App Services. At the time of this writing, you need at least level B1, which allows SSL connections.
In the Azure portal, you need to find the “SSL Settings” tab. Then click the “Upload Certificate” button to specify the certificate. You should then see it at the bottom of the screen:
Next, you need to provide your application with your certificates. This is done by adding the WEBSITE_LOAD_CERTIFICATES key to the Application Settings tab. You can use multiple thumbprint values separated by commas, or you can set this value to “*” to provide all of your certificates to your web application.
Protected Configuration Provider
Encryption and decryption is handled ProtectedConfigurationProvider. The one we are using in this article is called Pkcs12ProtectedConfigurationProvider. It was originally created by Microsoft but has been slightly modified to be compatible with Azure App Services.
The ProtectedConfigurationProvider inserts itself into the configuration reading pipeline, so your application code doesn’t really need to know about it. This is useful when you need the flexibility to use both encrypted and unencrypted configuration files.
You can add Pkcs12ProtectedConfigurationProvider directly to your project or download it using NuGet package WebConfigEncrypter. This article assumes that you will be using the NuGet package.
Preparing the web.config File for Encryption
After adding the Pkcs12ProtectedConfigurationProvider class to the project, you need to prepare the web.config file for encryption.
1. Add this section to your web.config file.
<configuration> [...] <configProtectedData> <providers> <add name="Pkcs12Provider" thumbprint="1234123412341234123412341234123412341234" type="WebConfigEncrypter.Pkcs12ProtectedConfigurationProvider, WebConfigEncrypter" storeLocation="LocalMachine"/> </providers> </configProtectedData>
2. Change the thumbprint attribute to match your certificate.
3. If you are not using the NuGet package, update the type attribute to match the fully quantified class and assembly name of your DLL.
Encryption of connection strings in the web.config file
Before you start doing this, make sure you have a backup copy of the file.
At the Visual Studio command prompt, type “where aspnet_regiis”. Then copy the following files to this folder. This will allow the aspnet command line tools to use your class
Then run this command from the same folder as the file
aspnet_regiis -pef "connectionStrings" "." -prov "Pkcs12Provider"
Your encrypted configuration section should look something like this:
<connectionStrings configProtectionProvider="Pkcs12Provider"> <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>Moy/a2XO2zvnn/HZW53DyC8aAJWo16+0KmnpC4SCSmuQZU0RT+HNFEA33pAGCzve+m6MTaRzhx6jVVRoAvpSNzfYG1bU1z7a1YnbW4OGxrmYYfdWW6cZQZ57dZnL6YSAlkJ5WlqPDGUPJa6FV/hTic3x4fJYy5vdSucmO6X3opuo1998LWNkL6fIS4WkjkG/SOFbI2Qx3HHogdN670jDHKNDON1z7bFHhLNyVj7RTO3xuQN9kF4PqbFtvwm1bYXTbZpdNxu/fcXZKONSAu8HN3QX5vTRyP/I4BG+NK7TUig3gxD4tq9GR7aSSGKJyt02PiCEO0JpyyIbHZ9xbck9kw==</CipherValue> </CipherData> </EncryptedKey> </KeyInfo> <CipherData> <CipherValue>TeV0yJaFlEhpyZUlQoG7M3O7sfQ7uG3ndgmhxipOrwoEsrI+Zvt1NI7arefOFWGNW4CEaoLo4mKy2Kwr4ZgK+6rAwOmx1IRyheWtF7z/8+CiGOqSRXLyGEkDQBEVOWKU0Y6TaWtPu0ZM3bp5pvKaztBnthgGnrGYmigaufu5rZW1GWPtHyL2iWdAkU9iaf+AOpA/GSvoVtZmnfJ1rwy6U8PTO0h0Ws/PdkcOKuXGkx31t/Y32ivFoy7xYPnPt/Z/aNMiHvbO7faQAwuJ/NsG9G1FFRRHCqc73TUsRdKHVuf17BEp526RG6RBZtM3F3V3o0d8/sLmyrNI9tFfksB4qcWiN4P+BRtGr0iacmBfBOvAFSozfUYxjMpx+BYPOpD1pf4fMFoKxxKeJYY31XqZoQLp75RgmWhWYm8URHq4Cjs=</CipherValue> </CipherData> </EncryptedData> </connectionStrings>
That’s it (for Windows IIS). Key
configProtectionProvider will tell your application which decryption class and certificate to use. If that doesn’t work, re-run the Import-PfxCertificate command above.
Encryption of user configuration sections
In addition to connection strings, you can encrypt custom configuration sections created with IConfigurationSectionHandler. To do this, you need to copy the library that defines the custom configuration class to the same folder as aspnet_regiis, just like you did with
Make sure you use the fully quantified class and assembly name for your custom configuration class in your configSections list. For example:
<configSections> <section name="protectedSettings" type="MyConfigSectionHandler.MyHandler, WebApplication1" /> </configSections>
This is necessary for
aspnet_regiiseven though otherwise you can just specify the class name.
You can then run the encryption command again by replacing the -pef parameter with the partition name.
aspnet_regiis -pef "protectedSettings" "." -prov "Pkcs12Provider"
Special Considerations for Azure App Services
Azure Since Azure App Services stores and provides certificates for the current user and not for the machine, you will need to change the attribute
<add name=“Pkcs12Provider” thumbprint=“1234123412341234123412341234123412341234" type=“WebConfigEncrypter.Pkcs12ProtectedConfigurationProvider, WebConfigEncrypter” storeLocation=“CurrentUser”/>
The translation of the article was prepared on the eve of the start of the C# ASP.NET Core developer course. We invite everyone to free course lesson, in which we will get acquainted with the types of databases. We will analyze how to work with relational and non-relational databases – directly and through ORM. Registration is available at link.