As developers, we should all care about security and how we store and use sensitive data, to either connect to the databases or login to domain accounts etc.
Today, I'm going to discuss how to encrypt usernames and passwords that are stored and saved via an application's app.config. This article will use a custom configuration section called EncryptUserCredentials. I won't discuss here how I created that, but here is a sample app.config showing it. Please note.
- service - key value to the record.
- userName - username.
- password - password.
- <?xml version="1.0" encoding="utf-8"?>
- <configuration>
- <configSections>
- <section name="CustomConfig" type="garfbradaz.Common.CustomConfigSections.EncryptedUserCredentialsSection, garfbradaz.Common" />
- </configSections>
- <appSettings>
- </appSettings>
- <startup>
- <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0" />
- </startup>
- <CustomConfig>
- <EncryptedUserCredentials>
- <EncryptedUserCredential service="keyToCredential" userName="firstname.lastname" password="pwd12345@" />
- </EncryptedUserCredentials>
- </CustomConfig>
- /configuration>
I will not show you the implementation details and how you would access this in code, until another post. Today, we will discuss how you can encrypt the EncyptedUserCredentials themselves, because at the moment they are plain text for all to see!
The way you accomplish this is, by using aspnet_regiis.exe, which, all you ASP.NET web developers already know, registers your web applications with IIS.
But wait. There are other functions dandy binary brings and that is encrypting sections in web.configs.....
But I'm using an App.Config silly:
That's right. That doesn't matter. They are just config files to .NET, but with different names. So, let me explain what you need to do. But before that, here is where aspnet_regiis is located on your Windows box:
Version of .NET Framework | Location of Aspnet_regiis.exe file |
---|
.NET Framework version 1 | %windir%\.NET\Framework\v1.0.3705 |
.NET Framework version 1.1 | %windir%\Microsoft.NET\Framework\v1.1.4322 |
.NET Framework version 2.0, version 3.0, and version 3.5 (32-bit systems) | %windir%\Microsoft.NET\Framework\v2.0.50727 |
.NET Framework version 2.0, version 3.0, and version 3.5 (64-bit systems) | %windir%\Microsoft.NET\Framework64\v2.0.50727 |
.NET Framework version 4 (32-bit systems) | %windir%\Microsoft.NET\Framework\v4.0.30319 |
.NET Framework version 4 (64-bit systems) | %windir%\Microsoft.NET\Framework64\v4.0.30319 |
Before we move on, I must tell you we are focusing on a multi-machine configuration file encryption using RSA. If your application is running on one machine only, then you can use DPAPI and its provider DataProtectionConfigurationProvider. DPAPI is handled by Windows itself and uses specific machine keys and containers. These are not transferable to different machines. If you wanted to use the DPAPI method for a multi-machine scenario, aspnet_regiis would need to be run on an app.config on each machine it is deployed on.
Why! Is that a bad thing?
Simple. You would need to store a plain text app.config file as either part of the continuous integration process or someone would need to manually keep a copy and run it on each machine, or even include the plain copy in the installer if that was your method for deploying. This just adds a security weak point. You could include scripts to delete the plain text files, if this is the route you wanted to go down. But, just so you know, DPAPI exists and could be a better option for you.
RSA route
So, aspnet_regiis allows you to create containers of asymmetric private/public keys and export them to other machines, allowing you one global config file to be used.
Step 0 - Preperation is (RSA) key
Yes- yes. Step 0 exits because I got half way and forgot this step. Thank the stars, it was meant to be Step1! Add a configProtectedData section to your config with provider. Please note:
- keyContainerName - should be the name of the RSA container you will create later.
- name - Can be anything. Im naming mine MyEncryptionProvider.
- <?xml version="1.0" encoding="utf-8"?>
- <configuration>
- <configSections>
- <section name="CustomConfig" type="garfbradaz.Common.CustomConfigSections.EncryptedUserCredentialsSection, garfbradaz.Common" />
- </configSections>
- <appSettings>
- </appSettings>
- <startup>
- <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0" />
- </startup>
- <CustomConfig>
- <EncryptedUserCredentials>
- <EncryptedUserCredential service="keyToCredential" userName="firstname.lastname" password="pwd12345@" />
- </EncryptedUserCredentials>
- </CustomConfig>
- <configProtectedData>
- <providers>
- <add keyContainerName="MyCustomKeys"
- useMachineContainer="true"
- name="MyEncryptionProvider"
- type="System.Configuration.RsaProtectedConfigurationProvider"/>
- </providers>
- </configProtectedData>
- </configuration>
Step 1 - Espionage
Yes, I said aspnet_regiis won't have a problem with an App.config - it won't, but first you need to rename/copy said App.config file to web.config.
- copy app.config web.config
Step 2 - Rise and Serve
Create a public/private RSA key pair with a specfic container name. They should also be marked as exportable (otherwise, what is the point!). MyCustomKeys can be any name you desire.
- aspnet_regiis.exe -pc MyCustomKeys -exp
Step 3 - Let me in!
Grant permissions for accounts to access the container. Example here is the network service IIS uses.
- aspnet_regiis.exe -pa MyCustomKeys "NT AUTHORITY\NETWORK SERVICE"
Step 4 - Encrypt and Protect
Now, the magic happens. The following line will now encrypt your section (my EncryptedUserCredentials are wrapped in section CustomConfg). The -pef switch is telling the application to look for a web.config file and to use my provider I declared in Step 0 (which is using type RsaProtectedConfigurationProvider).
- aspnet_regiis.exe -pef CustomConfig . -prov MyEncryptionProvider
You web.config file should now have transformed. Gone is the CustomConfig section with plain text credentials. Now, there is a nice CyperValues. Please note, mine below have been replaced with hard coded text, but you will see what I mean when you do yours. Also note that your CustomConfig section now declares it uses a configProtectionProvider=MyEncryptionProvider.
- <?xml version="1.0" encoding="utf-8"?>
- <configuration>
- <configSections>
- <section name="CustomConfig" type="garfbradaz.Common.CustomConfigSections.EncryptedUserCredentialsSection, garfbradaz.Common" />
- </configSections>
- <appSettings>
- </appSettings>
- <startup>
- <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0" />
- </startup>
- <CustomConfig configProtectionProvider="MyEncryptionProvider">
- <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#tripledes-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>Rsa Key</KeyName>
- </KeyInfo>
- <CipherData>
- <CipherValue>longstringofdata</CipherValue>
- </CipherData>
- </EncryptedKey>
- </KeyInfo>
- <CipherData>
- <CipherValue>anotherlongstringofdata</CipherValue>
- </CipherData>
- </EncryptedData>
- </CustomConfig>
- <configProtectedData>
- <providers>
- <add keyContainerName="MyCustomKeys"
- useMachineContainer="true"
- name="MyEncryptionProvider"
- type="System.Configuration.RsaProtectedConfigurationProvider"/>
- </providers>
- </configProtectedData>
- </configuration>
Step 5 - Export those Keys
So now, we have created our web.config file. You can rename it to app.config and use this in your application. To use it on different machines though, you will need to export the keys from the machine that you created the encrypted web/app.config file with and import them onto each machine. Firstly on your machine run the following which will create the key file for your container, including the private keys (-pri).
- aspnet_regiis.exe -px MyCustomKeys keys.xml -pri
Step 5 - Import those Keys
Log into the machine(s) you wish your application to work on and run the following,
- aspnet_regiis -pi MyCustomKeys keys.xml
I would do this as part of your Release or Installation process making sure you delete the keys.xml file from the installed machines. The only place the keys.xml should be kept is in your code repository store but somewhere safe where it is restricted. This is the security issue for the RSA approach.
The full encrypt and export script can be found here. Amend it to include your custom container, section, and provider names.
- GOTO EndComment
- This batch file will encrypt a app.config file using aspnet_regiis. You can use other windows directories to run
- the application depending on which version you have installed.
- The batch file assumed you have app.config file incuded in the direcorty you are running the batch file AND has been amended to
- include the appropriate provided.
-
- See this article on details on how to setup the config etc and what each command does
-
- https://mywebanecdotes.com/2016/09/17/encrypting-credentials-in-app-config-for-multiple-machines/
-
- The article describes on how to import the keys to different machnes as well.
- :EndComment
- cd %~dp0
- copy app.saved.config web.config
- %windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_regiis.exe -pc MyCustomKeys -exp
- %windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_regiis.exe -pa MyCustomKeys "NT AUTHORITY\NETWORK SERVICE"
- %windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_regiis.exe -pef CustomConfig . -prov MyEncryptionProvider
- %windir%\Microsoft.NET\Framework64\v4.0.30319\v4.0.30319\aspnet_regiis.exe -px CustomKeys keys.xml -pri
- pause
If you like my blog post, please
like my Facebook Page to receive more.
Reference - https://msdn.microsoft.com/en-us/library/k6h9cz8h.aspx