How to encrypt connection string in app.config

T.Zacks 3,986 Reputation points
2021-02-15T17:07:20.847+00:00

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

C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,364 questions
0 comments No comments
{count} votes

2 answers

Sort by: Most helpful
  1. Art 6 Reputation points
    2021-02-15T23:07:11.92+00:00

    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:

    1 person found this answer helpful.

  2. Karen Payne MVP 35,196 Reputation points
    2021-02-15T17:31:36.333+00:00

    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