How to encrypt and decrypt custom configuration files (XML files) in C# - c#

I am new to the forums.
I've just started working on C# and webservices for the past 3 months and I've got a great web service rearing to go. Unfortunately, there is a custom "configuration" file (really an XML file) that we use to store our connection strings.
We don't want to use the web.config connectionstring section because the class and the associated xml file that was written in house, will be used by other projects not just web services. The problem is I need to encrypt the username and passwords of the "configuration" XML file and decrypt it in my C# code.
Suffice to say the XML file has the following structure ...
<?xml version='1.0'?>
<!--
TEST ENVIRONMENT
-->
<thesystem>
<connectionString string="Data Source=( DESCRIPTION = ( ADDRESS_LIST = ( ADDRESS = ( PROTOCOL = TCP )( HOST = {0} )( PORT = {1} ) ) )( CONNECT_DATA = ( SERVER = DEDICATED )( SERVICE_NAME = {2} ) ) ); User Id= {3}; Password = {4};"/>
<oracleDetails>
<site name="thesite">
<schema dbname="thedb" dbHost="99.99.99.99" dbPort="9999" dbServiceName="SYSTEMSITE" dbUsername="xxx" dbPassword="yyy"/>
</site>
</oracleDetails>
</thesystem>
I've looked on the web and managed to "cheat" around a way to encrypt the file using aspnet_regiis.exe
ie:
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727>aspnet_regiis -pef oracleDetails . -prov DataProtectionConfigurationProvider
Encrypting configuration section...
Succeeded!
I got this to work by renaming the tag to and renaming the xml file to web.config. I tricked ASP.net to think I am encrypting a web configuration file.
The problem now is how do I decrypt it in C#?
I've tried using the following ...
Configuration _myConfig = ConfigurationManager.OpenExeConfiguration("OURSYSTEM.config");
where OURSYSTEM.config is the XML file above.
It program throws an error saying it cannot locate the file. And besides, the OpenExeConfiguration is more for Win apps with the app.config file.

After you run the aspnet_regiis -pef oracleDetails . -prov DataProtectionConfigurationProvideris the config XML encrypted? Most likely it is, and problem then is that your ASP.Net cannot decrypt it and that ultimately is a key access issue. Make sure you encrypt it using credentials the app pool has access to. Ie. if your ASP app pool runs as user foo, then you must run aspnet_regiis as the same user.

Related

Will Aspnet_regiis encrypt connection string info stored in an external config file?

Right now we need a secure place to put our connection strings. We would like to place these connection strings in an external file separate from Web.config to make deployments easier, but we also want the information inside to be encrypted for security.
Is there any way to accomplish this using the Aspnet_regiis tool? I understand how to use it to encrypt sections within the Web.config file, and we like how encrypting with this method means that decryption happens for us automatically when the site is being used. But the information I find on this subject seems conflicting.
Encrypt custom config section in ASP.NET using aspnet_regiis
This link to another question seems to suggest that all I have to do is set the external config file up like normal, place the sensitive connection string info inside of it, and run the Aspnet_regiis tool as normal and the external file will be encrypted.
http://www.velocityreviews.com/forums/t722875-encrypting-external-config-section.html
However the response in that link states that Aspnet_regiis cannot be used to encrypt external sections.
So can this be done, and if not, is doing all of this programatically the only way to go?
I just tried this myself, and I can confirm that the Aspnet_regiis tool WILL indeed encrypt connection strings stored in an external config file. In the Web.config file I referred to the externally-defined connection strings using the "configSource" attribute, and they were encrypted after running the tool.
You can encrypt connection string using C#
ExeConfigurationFileMap configMap = new ExeConfigurationFileMap();
configMap.ExeConfigFilename = modulePath + "Web.Release.config";
System.Configuration.Configuration config = ConfigurationManager.OpenMappedExeConfiguration(configMap, ConfigurationUserLevel.None);
System.Configuration.ConfigurationSection section = config.GetSection("connectionStrings");
if (!section.SectionInformation.IsProtected)
{
section.SectionInformation.ProtectSection("RsaProtectedConfigurationProvider");
config.Save();
}

Connection string data source path to access files from other projects

i have 2 projects , 1 is a web application and another is WPF , in my web application i have a upload page to allow users to upload their files i used Server.MapPath(#"~/something/") for the directory but how do i retrieve that file in my WPF application , i can retrieve by typing the full path C:/programfiles/projects ... etc , but i am retrieving the directory from the database and in the database it reads like that ~/something/filename.jpg .
I only save ~/something/filename.jpg in the database , How do i retrieve the full path without manually typing the full path?
the Full path is in another project like this C:/programfiles/projects/visualstudio/projectname/something/filename.jpg.
How to i access the file with only ~/something/filename.jpg in another project? there is an error saying path does not exists unless i type the full path in but i don't want that .
Some say we have to add a domain directory in the connectionstring of my App.Config then later i need to use it and combined it with the database url to get my full path . But i got no idea how to do that .
connectionstring :
<add name="istellarEntities2" connectionString="metadata=res://*/ModelSQL.iStellar.csdl|res://*/ModelSQL.iStellar.ssdl|res://*/ModelSQL.iStellar.msl;provider=System.Data.SqlClient;provider connection string="data source=IMAC-PC10\SQLEXPRESS;initial catalog=istellar;integrated security=True;multipleactiveresultsets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />
How i retrieve from my database ( the URL , using entity framework daoWordPuzzle is a class file which consists of CRUD codes ) :
#daoWordPuzzle.GetfileURL() // however this displays only ~/something/something.jpg
I need to have the full path . How do i do that?
Firstly, a quick question: Is your WPF application running on the WEB SERVER that also runs the website?
Or is your WPF app on a desktop and web server is somewhere else?
In the first case: You can simply store the first part of the path in appSettings of your WPF application to tell you where the directory is. For example and store only the last part of the path in the database column. This way you can use Path.Combine() from System.IO namespace to find the location.
The same approach can be used in the other case, but it depends on if you have UNC share to the web server directory that stores the files. If not, your WPF app may need to access the files via HTTP using a URL instead of file path. If yes, you can simply store the path prefix in the app config like so "\WEBSERVER\Something"
using System.Configuration;
string fileUploadDirectory = ConfigurationManager.AppSettings["FileUploadDirectory"];
// using Substring(1) to skip the ~ that is stored in the database and is returned by GetfileURL()
string fullFilePath = Path.Combine(fileUploadDirectory ,daoWordPuzzle.GetfileURL().Substring(1))

Encrypt connection string in app.config

I am having trouble encrypting a connection string in app.config. I have code that will protect the connectionStrings section of app.config, but the password is still displayed in plain text.
I need to encrypt the connection string in so it is not in plain text when deployed. I see similiar questions on SO for web.config, but not app.config.
You can easily apply the same solution as the web.config you just have to rename your app.config to web.config, encrypt with the aspnet_regiis tool and then rename it back to app.config.
Rename app.config to web.config
Open command prompt and type:
%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_regiis -pef "connectionStrings" c:\<folder containing your web.config>
(stop at folder level and don't put the trailing "")
rename web.config back to app.config
You can open it in notepad to see the encrypted file. In visual studio you will see it's decrypted. You can use your connection string the same way as if it was not encrypted. (Note that it can only be decrypted on the same machine it's encrypted on.)
Have a look at This Article it has some very useful examples. You're basically looking for System.Configuration.SectionInformation.ProtectSection to help you out here.
Also have a peek at Implementing Protected Configuration
• Rename App.config file to web.config<br>
• Run Command prompt as admin:
For encrypt:
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_regiis.exe -pef "connectionStrings" your project location within quotes and -prov "DataProtectionConfigurationProvider"
Ex:
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_regiis.exe -pef "connectionStrings" "D:\location\location1\location" -prov "DataProtectionConfigurationProvider"
For Decrypt:
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_regiis.exe -pdf "connectionStrings" your project location within quotes.
Ex:
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_regiis.exe -pdf "connectionStrings" "D:\location1\location"
For error:
Add this in Configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0"
Like this:
• Finally, Rename web.config to App.Config
Additionally, If there is anyone who wants to encrypt and decrypt connection strings in web farms here are the steps:
Create an RSA key:
aspnet_regiis -pc "MyKeys" -exp
Grant access for application pool identity to this key:
aspnet_regiis -pa "MyKeys" "IIS AppPool\ApplicationPoolName" -full
Add RSA provider to the web.config:
<configuration>
<configProtectedData>
<providers>
<add name="MyProvider"
type="System.Configuration.RsaProtectedConfigurationProvider, System.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"
keyContainerName="MyKeys"
useMachineContainer="true" />
</providers>
</configProtectedData>
</configuration>
Encrypt web.config by using the RSA provider:
aspnet_regiis -pe "connectionStrings" -app "/MyApplication" -prov "MyProvider"
Note: You can use the alternative syntax like the one we did for a single server scenario. Example:
ASPNET_REGIIS -pef "connectionStrings" "D:\inetpub\wwwroot\applicationFolder" -prov "MyProvider"
Open the web.config and confirm that the connection string is encrypted
Test the site and confirm that it is working
Try decrypting the web.config. Create a test.aspx file with the code below inside. Browse it to see the decrypted file
Export the RSA key to the C drive:
aspnet_regiis -px "MyKeys" "c:\keys.xml" -pri
Copy this file to the second server in the web farm
Import it in that server:
aspnet_regiis -pi "MyKeys" "c:\keys.xml"
Grant access to this key (same as Step 2)
Test the application in the second server
Source: How to encrypt and decrypt connection strings
Define the location of config File
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
if you want to encrypt connectionStrings
config.ConnectionStrings.SectionInformation.ProtectSection(Nothing);
you must be aware of app config portions
so if you want to encrypt AppSettings
config.AppSettings.SectionInformation.ProtectSection(Nothing);
A way to automate this:
ProjectSettings > Compile > BuildEvents > Edit Post-build
Paste the code below:
SET ApplicationName=YourAppWithoutExtention
echo.
echo POST BUILD ACTIONS
echo ====================
if EXIST web.config (
echo Deleting web.config
DEL web.config
)
echo Renaming %ApplicationName%.exe.config to web.config
REN %ApplicationName%.exe.config web.config
echo Running aspnet_regis against webconfig
SET rpath=%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_regiis -pef "connectionStrings" "$(TargetDir)
SET rpath=%rpath:~0,-1%"
echo Path: %rpath%
%rpath%
echo Renaming web.config to %ApplicationName%.exe.config
REN web.config %ApplicationName%.exe.config
echo Done.
Replacing "YourAppWithoutExtention" with your app name.
Then every time it builds, it will automatically encrypt your app.config.
After hours of researching solutions related to the question.
I found a reasonable solution:
The problem with your approach is that your app will need to contain
both a decryption key and a decryption algorithm in order to decrypt
and use the connection string.
It would be dangerous to assume that even a junior developer won't be
able to just debug the code, step through the decryption and get the
unencrypted string at the end.
Storing secrets (like connection strings, passwords, API keys) in
config files is strongly discouraged as it's a very insecure practice.
Instead you should be using a "secrets manager" service -- it's a
secure online service that can store your passwords and lets you
retrieve them when needed.
When using a secret management service, no secrets or decryption key
or algorithm is stored in your source code. Retrieving a secret is as
simple as this:
For Azure Key Vault:
var keyVaultUrl = "https://<your-key-vault-name>.vault.azure.net/";
var credential = new DefaultAzureCredential();
var client = new SecretClient(vaultUri: new Uri(keyVaultUrl), credential);
KeyVaultSecret secret = client.GetSecret("<your-secret-name>");
Console.WriteLine($"{secret.Name}: {secret.Value}");
For AWS Secrets Manager (skipped some error handling code):
var client = new AmazonSecretsManagerClient(accessKeyId, secretAccessKey,
RegionEndpoint.APSoutheast2);
var request = new GetSecretValueRequest {
SecretId = secretName
};
GetSecretValueResponse response = null;
response = client.GetSecretValueAsync(request).Result;
You can also search for an alternative secret manager and implementation like Google Cloud Secret Manager or others.
This approach has lots of advantages over the storage of secrets locally:
you don't have to mess with storing different values in configs for Prod/Staging/Dev environments -- just read appropriately named secrets (such as '[Dev|Prod|Stag]DBPassword`
only selected few people can have access to the very important secrets (such as, I dunno, say an authorisation code to transfer all $$$ from Deus account to E-Coin wallets around the world #revolution), and their access can be revoked at any time
if anyone steals your source code (disgruntled employee, accidental leak) none of your passwords have been leaked
changing a password is easy -- you just update it using the could management console and restart the app(s)
How to use AWS Secrets Manager to store & read passwords in .Net Core apps
How to securely store and retrieve sensitive info in .NET Core apps with Azure Key Vault
Credits and thanks to #smartial-arts Reference; the second answer.

problem with encryption & decryption connectionStrings

I used the following command to encrypt my connection string but an error ocurred
"The connection name
'DatabaseConnectionString1' was not
found in the applications
configuration or the connection string
is empty"
How can I encrypt it while keeping the application working?
The command used was
aspnet_regiis -pef "connectionStrings" "C:\Users\ANAS\Documents\Visual Studio 2008\WebSites\WebSite7"
What if I move the encrypted application to another computer? Will it work?
How can I encrypt it while keeping the
application working?
You can't. If you change your web.config your application is initialized.
What if I move the encrypted
application to another computer? Will
it work?
It will not work. You can only encrypt config sections on the same machine you decrypted it before. That's the reason why this is secure: You can't take a config file away and decrypt it on another machine.

Encrypting class library app.config file

Please share your thoughts if there is any way to encrypt app.config section with out changing code? I know that we can use aspnet_regiis.exe to encrypt the web.config file.
I came across some blogs to rename app.config to web.config and run aspnet_regiis -pef command. I am able to create an encrypted version of app.config file but application failed to read the keys from encrypted app.config. so this approach didnt work for me.
Many thanks
What about this way? Are you able to do that?
Encrypt your connection strings and stored procedure names in app.config. (Use like tripleDes)
Store your encrypted values in app.config.(like: ConnectionString="asdasfasfasfdsdgsdfa")
After reading value from app.config, decrypt it with your service and use.
by the way I found my old answer about ready to use Crypto Class :)
.NET: what are my options for decrypting a password in my project .setting file

Categories