Config dosyasında şifreli veri


Bu gün işinize yarayacağına inandığım bir konudan bahsetmek istiyorum. Windows service yazdıysanız ve servisin kullandığı şifreniz var ise şifreyi kodamı gömeceğim sorusunu sanırım sormuşsunuzdur. bu noktada farklı alternatifler düşündüm ilki , servis'e çalıştırma anında parametre olarak geçmekti, ancak bir sıkıntısı vardı ve restart sonrası müdehale zorunluluğu doğuyordu. şifreyi gizledik ama pratik olmadığı kesin. :)

Sonra config dosyasına gömmek aklıma geldi pratik ama güvenli değildi, appSettings ve ConnectionString komple şifrelemek "isProtected", "protect" ve "unProtect" methodları ile basit ancak sadece bir parametreyi şifrelemek...  peki ne yapalım derken bir parametre daha ekleyip onun değerine göre şifreyi encrpted hale getirip config dosyasını update etmek yine başka bir değere göre açmak aklıma geldi. (bu 2. parametre koda gömülü size özel bir parolada olabilir.)

Yazımda bahsettiğim yapıya göre çalışa bilecek bir dll library projesi için gerekli yapıyı aktaracağım.

İlk adım olarak gerekli method ları tasarlayalım ;

1 - Encryption/Dycription için birer method gerekecek. Bu kısımda en saitinden yola çıkacağız ancak gerçek hayatta kendi encryption dll varsa onu yada 3des veya benzeri bir çözüm kullanmanız mümkün.

private string encryptValue(string value)
        {
            string result = value;
            try
            {
                result = "*" + Convert.ToBase64String(ProtectedData.Protect(Encoding.Unicode.GetBytes(value), null, DataProtectionScope.LocalMachine));
            }
            catch (Exception e)
            {
EventLog.WriteEntry("simpleConfigEncryption", "encryptValue Hata :  " + e.StackTrace, System.Diagnostics.EventLogEntryType.Error, 0);
            }
            return result;
        }
        private string decryptValue(string value)
        {
            string result = value;
            try
            {
                if (result.IndexOf("*") >= 0)
                {
                    result = result.Remove(0, 1);
                    result = Encoding.Unicode.GetString(ProtectedData.Unprotect(Convert.FromBase64String(result), null, DataProtectionScope.LocalMachine));
                }
            }
            catch (Exception e)
            {
EventLog.WriteEntry("simpleConfigEncryption", "decryptValue Hata :  " + e.StackTrace, System.Diagnostics.EventLogEntryType.Error, 0);
            }
            return result;
        }

NOT : Değerin encrypted yada clear-text olduğunu sorgulamak adına bir method ihtiyacımız olacak. Bu adımda basit ve birazda uyduruk bir yol izleyerek encrypted halin başına "*" karakteri koyuyoruz ve bu sorgu için basit bir method yaratıyoruz. Bu methodun da şu şekilde olduğunu düşünelim ;

private bool isEncrypted(string value)
        {
            bool result = false;
            if (value.Substring(0, 1) == "*")
                result = true;
            return result;
        }

2 - Config okuması kolay ancak, En önemlisi config dosyasını update etmek. Bu noktada aşağıdaki şekilde bir kod işimizi görecektir;

private void updateAppSettings(string key, string value)
        {
            try
            {
                string appPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
                string configFile = System.IO.Path.Combine(appPath, AppDomain.CurrentDomain.SetupInformation.ConfigurationFile.);
                EventLog.WriteEntry("simpleConfigEncryption", "updateAppSettings  :  " + configFile, System.Diagnostics.EventLogEntryType.Information, 0);
                ExeConfigurationFileMap configFileMap = new ExeConfigurationFileMap();
                configFileMap.ExeConfigFilename = configFile;
                System.Configuration.Configuration config = ConfigurationManager.OpenMappedExeConfiguration(configFileMap, ConfigurationUserLevel.None);
                config.AppSettings.Settings[key].Value = value;
                config.Save();
            }
            catch (Exception e)
            {
                EventLog.WriteEntry("simpleConfigEncryption", "updateAppSettings Hata :  " + e.StackTrace, System.Diagnostics.EventLogEntryType.Error, 0);
            }
            finally {}
        }

Dikkat ettiyseniz, bu adıma kadarki tüm method' larımızı private olarak tercih ettik, zira bu kısmı dış dünyaya açmanın bir anlamı olacağını düşünmüyorum.

3 - Bu adımda dış dünyaya açacağımız, ve "appsettings" kısmındaki ilgimizi çeken parametrenin adını alan bir method oluşturuyoruz;

public string encryptDecryptAppStringParameter(string key)
        {
            string result = "";
            int option = 0;
            try
            {
                option = int.Parse((ConfigurationManager.AppSettings["isAlive"].ToString() == "1" ? "1" : "0"));
            }
            catch { option = 0; }
            try
            {
                Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
                ConfigurationSection section = config.GetSection("appSettings");
                result = ConfigurationManager.AppSettings[key].ToString();

                if (isEncrypted(result))
                {
                    result = decryptValue(result);
                    if (option != 1)
                    {
                        updateAppSettings(key, result);
                    }
                }
                else
                {
                    if (option == 1)
                    {
                        updateAppSettings(key, encryptValue(result));
                    }
                }
            }
            catch(Exception e)
            {
                EventLog.WriteEntry("simpleConfigEncryption", "Hata :  " + e.StackTrace, System.Diagnostics.EventLogEntryType.Error, 0);
                result = ConfigurationManager.AppSettings[key].ToString();
            }
            return result;
        }

Dikkat edilecek bir husus, daha öncede belirttiğim alacağımız aksiyonu kontrol amaçlı "isAlive" isimli bir parametre daha kullanmış olmamız, ancak bu parametre için "0/1" den daha farklı bir kontrol yapılabilir, hatta ufak müdehaleler ile baait bir şifre gömülebilir. Böylece çıktı olarak ürettiğimiz dll referans olarak bir projeye  eklendikten ve "isAlive" parametresi de (yada muadili) oluşturulduktan sonra, dll ile oluşturacağınız bir obje ile ilgili methodumuzu çalıştırırken, şifre bilgisini içeren "appsettings" parametresinin adını veriyor olmanız yeterli olacak. kullandığınız encryption algoritmasına göre yeterli oranda güvenlik elde edebilirsiniz. Bu ara parametrenin opsiyonel olarak açılması şart değil, isteğe bağlı olarak bu kısmı kapatabilirsiniz. Sadece kendiniz için bir arka kapı ihtiyacına binayen göstermek istedim. Tüm yazının özeti şöyle, kolaylıkla entegre edilebilecek basit bir dll ile aslında config dosyasına koyduğumuz hassas bilgilerimizi servis veya uygulamamızın ilk çalışmasın anında encrypted olarak güncelleyen ve saklayan bir yapımız olabilir.  😁

Yorumlar

Yazılar

Kotlin - 1 - Giriş

Genesys Nuance-ASR Entegrasyonu Port Kullanımı

Kotlin - 5 - Dönüşler ve Atlamalar (Returns and Jumps)