question

TZacks-2728 avatar image
0 Votes"
TZacks-2728 asked LukePoga-1949 published

How to encrypt connection string in app.config

I am using winform application.

I am looking for approach by which i can encrypt a connection string in app.config file in such a way which a developer can not decrypt.
if can use any encryption logic to encrypt connection but the problem is when i will use sql connection object then i have to decrypt connection string first and pass that readable connection to sql connection object which any developer debug the code and will be able to know what is connection string.

so please tell me any approach where i can pass encrypted connection string to sql connection object and sql connection object has one connection string property which will not reveal the actual connection string.

please tell me best approach as a result once i encrypt connection string other developer will not be able to know the connection just debugging the code.

Thanks

dotnet-csharp
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

karenpayneoregon avatar image
0 Votes"
karenpayneoregon answered LukePoga-1949 commented

Hello,

Least desirable


Even though encrypting/decrypting connection string is not wise, here is a class for it. Add a reference for System.Configuration to the project following by adding this class.

 public class ConnectionProtection
 {
     public string FileName { get; set; }
     /// <summary>
     /// Determine if configuration file exists for application
     /// </summary>
     /// <param name="FileName">Current executable and path</param>
     public ConnectionProtection(string FileName)
     {
         if (!File.Exists(string.Concat(FileName, ".config")))
         {
             throw new FileNotFoundException(string.Concat(FileName, ".config"));
         }
            
         this.FileName = FileName;
     }
     /// <summary>
     /// Encrypt ConnectionString
     /// </summary>
     /// <param name="encrypt"></param>
     /// <param name="fileName"></param>
     /// <returns></returns>
     private bool EncryptConnectionString(bool encrypt, string fileName)
     {
         bool success = true;
         Configuration configuration = null;
    
         try
         {
             configuration = ConfigurationManager.OpenExeConfiguration(fileName);
             var configSection = configuration.GetSection("connectionStrings") as ConnectionStringsSection;
    
             if ((!(configSection.ElementInformation.IsLocked)) && (!(configSection.SectionInformation.IsLocked)))
             {
                 if (encrypt && (!configSection.SectionInformation.IsProtected))
                 {
                     // encrypt the file
                     configSection.SectionInformation.ProtectSection("DataProtectionConfigurationProvider");
                 }
    
                 if ((!encrypt) && configSection.SectionInformation.IsProtected) //encrypt is true so encrypt
                 {
                     // decrypt the file. 
                     configSection.SectionInformation.UnprotectSection();
                 }
    
                 configSection.SectionInformation.ForceSave = true;
                 configuration.Save();
    
                 success = true;
    
             }
         }
         catch (Exception ex)
         {
             success = false;
         }
    
         return success;
    
     }
     public bool IsProtected()
     {
         Configuration configuration = ConfigurationManager.OpenExeConfiguration(FileName);
         var configSection = configuration.GetSection("connectionStrings") as ConnectionStringsSection;
         return configSection.SectionInformation.IsProtected;
     }
     public bool EncryptFile()
     {
         if (File.Exists(FileName))
         {
             return EncryptConnectionString(true, FileName);
         }
         else
         {
             return false;
         }
     }
     public bool DecryptFile()
     {
         if (File.Exists(FileName))
         {
             return EncryptConnectionString(false, FileName);
         }
         else
         {
             return false;
         }
     }
 }

Create an instance of the class

 private ConnectionProtection _operations = 
     new ConnectionProtection(Application.ExecutablePath);


To protect

 if (!_operations.IsProtected())
 {
     _operations.EncryptFile();
 }


To get the connection string (here it's called ConnectionString)

 var mainConnection = "";
 if (_operations.IsProtected())
 {
     _operations.DecryptFile();
     mainConnection = Properties.Settings.Default.ConnectionString;
     _operations.EncryptFile();
 }
 else
 {
     mainConnection = Properties.Settings.Default.ConnectionString;
     _operations.EncryptFile();
 }

Better idea

See my Microsoft TechNet article: SQL Server database login for Windows Forms (C#) and GitHub source code repository.

Topics covered in the TechNet article.

68365-11111111111.png

Source code projects

68333-222222.png

Login window

68352-3333333333333.png








11111111111.png (24.8 KiB)
222222.png (7.8 KiB)
3333333333333.png (15.9 KiB)
· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

  var mainConnection = "";
  if (_operations.IsProtected())
  {
      _operations.DecryptFile();
      mainConnection = Properties.Settings.Default.ConnectionString;
      _operations.EncryptFile();
  }
  else
  {
      mainConnection = Properties.Settings.Default.ConnectionString;
      _operations.EncryptFile();
  }


Thanks madam for your answer. if i decrypt and assign the connection string to connection object then other people will be able to know what is connection string. basically i want other developer should not be able to see the connection string details.

show me how to assign connection string to connection object. please provide sample code. thanks

0 Votes 0 ·
smartial-arts avatar image
1 Vote"
smartial-arts answered LukePoga-1949 published

The problem with your approach is that your app will need to contain both decryption key and 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;

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)

I have written a couple of articles, showing how to set up and read secrets with AWS and Azure, feel free to check it out if you need step-by-step directions and complete source code:

· 4
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

The problem with your approach is that your app will need to contain both decryption key and decryption algorithm in order to decrypt and use the connection string.

Which is why I labeled it as least desirable. This is why I mentioned creating users in the server. Sure AWS is an option, same as Azure but dependent on usage both may be overkill as the person asking has not given enough details. Personally using AD group policies and or server users/roles seems the best way too go.
1 Vote 1 ·

Totally. I was however directing my response to the OPs question, apologies for any confusion, that was not meant to be read as criticism of your suggestion.

PS The current Q&A format is really not well suited for meaningful, threaded discussions, and this new platform suffers from that quite badly. For instance, people post follow up responses as "answers" instead of using comments. This is exacerbated by the lack of adequate moderation on MS part. It actually makes the new platform less useful than the older forums.asp.net that it's meant to replace.

0 Votes 0 ·
 r client = new AmazonSecretsManagerClient(accessKeyId, secretAccessKey, 
                                              RegionEndpoint.APSoutheast2);

So where do you store the accessKeyId, secretAccessKey? Its the same problem kicked down the road?



0 Votes 0 ·
 r client = new AmazonSecretsManagerClient(accessKeyId, secretAccessKey, 
                                              RegionEndpoint.APSoutheast2);

So where do you store the accessKeyId, secretAccessKey? Its the same problem kicked down the road?



0 Votes 0 ·