ASP.NET’de veri tabanlarına bağlantı kurarken connection string ifadesinin açık olarak, runtime da yada web.config de yazılması, yazılım güvenliği açısından risk oluşturacağından connection string ifadesinin açık olarak yazılması istenmeyen bir durumdur. Bu yüzden connection string ifadesinin şifrelenmesi gerekir. Aşağıda, şifreleme işlemi için iki yöntem önereceğim;
Web.config dosyasında Encrypt/Decrypt
Yöntemi : Bu yöntemde, Microsoft’un bize sunmuş olduğu kriptolama Tool ‘unu
anlatmaya çalışacağım. Bu Tool , “aspnet_regiis.exe” dir. Eğer bilgisayarınızda
.net framework 4 kurulu ise, “C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319”
gibi bir path içersine komut yorumlayıcısı(cmd) aracılığı ile girerseniz , bu
dosyayı görebilirsiniz. Kullanım için, cmd ile ilgili path e girdikten sonra
aşağıdaki kullanım komutlarını yazarak web.config içerisindeki “connectionStrings”
attribute unun şifrelenmesi yada şifresinin çözülmesi işlemlerini
yapabilirsiniz.
Generic olarak kullanımı;
a)aspnet_regiis -pe "connectionStrings"
-app "/SampleApplication" (SampleApplication pathindeki web.config
içindeki connectionStrings attribute unu kriptolar)
b)aspnet_regiis -pe
"connectionStrings" -app "/SampleApplication" -prov
"RsaProtectedConfigurationProvider" (SampleApplication pathindeki
web.config içindeki connectionStrings attribute unu specific provider
kullanarak kriptolar)
c)aspnet_regiis -pd "connectionStrings"
-app "/SampleApplication" (SampleApplication pathindeki web.config
içindeki connectionStrings attribute unun kriptosunu çözer.)
Şifreleme işlemini yaptıktan sonra, publish yapacağınız her ortam daki veri tabanı connection stringi değişiyorsa, ilgili ortamlar için connection string encrypt işlemini yapıp, sonra da web.config transformlarını yazmanız gerekmektedir!
Ayrıca şifreleme için default “RsaProtectedConfigurationProvider” kripto kütüphanesi kullanmadan custom RSA kripto kütüphanesi yazarsanız kendi kurumunuz yada şirketiniz adına size özel bir şifreleme yapmış olursunuz.Yazılım güvenlik seviyesini biraz daha artırmak istiyorsanız Custom RSA Provider yöntemini kullanabilirsiniz.
Örneğin, encryption öncesi web.config connection string değeri;
<connectionStrings>
<add name="DefaultConnection"
connectionString="Data Source=XXXXXXX;Initial Catalog=XXXXXXX;integrated
Security=true;"
providerName="System.Data.SqlClient" />
</connectionStrings>
Encryption sonrası web.config connection string değeri aşağıdakine benzer olur ve aşağıdaki örnekteki gibi transformu yazılabilir;
DB Connection string transform;
<connectionStrings
configProtectionProvider="XXXXXX"
xdt:Transform="Replace">
<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>hM3bWWJDSmoP+LNSnRgVbYxoA4Hk8wBtiGuIsTYSCTjob1G46JHuwbWqA3AugHWQF8gLrSdlHCYwUJBv6PCUheE1bfUxVkehAgrQdOjJc/0ehoma09GP/uTFCSaojZbdqIgSO0wI8B5ZR18N/Zp9sFxHWFD+RK+XwJ5nGwhjIWY=</CipherValue>
</CipherData>
</EncryptedKey>
</KeyInfo>
<CipherData>
<CipherValue>7WXzMYCceaTmpTQeeOX3EVDGely1kS0zmt3YsigERLXG6L5sAkm9rzSm9zetM0S08A4gdpFH4i+kfyKkUOG356nf+GRODD1mhkBLmFXGIqKeTdUrqdaeJvOBVRSk4hjJf1YSC5ZTXGMKZweCmswbgf1fQz+i8aaXH9Ci6dhKxE466oyos/vCuxayvc8Hgfl6N8P6HrCWZDqBcSWLoZybK5dVsKN+oX1knPHkyY7rO6vQrGDwtN2qORd3D/+NgadXMqlezmTVy+IEh/OlNdeU1reOx4/ZzjHb++RIM+clyVIGaM+zcZ5iNQ8skkJi62fENm+5+1fw8Z/cOzvK8d7mMgvYIYX0PUbcsnNEYRSRzg8Vtb4ble0gBHD40ULei4Q6</CipherValue>
</CipherData>
</EncryptedData>
</connectionStrings>
Windows Registry aracılığıyla Encrypt/Decrypt
Yöntemi : Bu yöntemde, connection string değeri runtime da registry den
decrypt edilerek okunur. Tabiki connection string ifadesinin daha önceden
registry de encrypt edilmiş halinin veritabanından veya uygulama sunucularından
sorumlu kişi tarafından kayıt edilmiş olması gerekmektedir.
Bu
yöntemi, yazılım geliştirme, veri tabanı ve sistem departmanlarının
sorumlulukları birbirinden bağımsız olarak tasarlanmış projelerde daha güvenli ve
daha esnek yöntem olarak kullanabilirsiniz. Projelerinizin genelinde
kullandığınız Encrypt ve Decrypt kütüphanelerini kullanarak connection string
in şifrelenmesi ve şifresinin çözülmesi işlemlerini istediğiniz güvenlik
düzeyine göre esnek olarak yapabilme imkanınız olacaktır. Böylece veri tabanı connection
sorumluluğunu her deployment ortamındaki sorumlu kişiye, development ortamından
bağımsız ve esnek olarak vermiş olursunuz. Tabiki, veri tabanı connection undan
sorumlu kişilere Registry ye connection string ifadesinin şifrelenmiş halini
kayıt edebilmeleri için, projelerinizde kullanmış olduğunuz Encrypt/Decrypt
uygulamasını vermeniz zorunlu olacaktır. Bu şekilde, veritabanı connection undan
sorumlu kişi veri tabanı connection string i değiştiği zaman registry den
ilgili connection string value sunu değiştirerek sorumluluğu tamamen üzerine
almış olacaktır.
Aşağıda,
ASP.NET Identity Framework DB Connection string inin runtime da Windows Registry
‘den decrypt edilerek okunması örneği yapılmıştır;
Registry e yazacağımız
Connection string path ini Web.config içerisinde ki <configration>
attribute unun altına aşağıdaki şekilde tanımlıyoruz;
<appSettings>
<add key="ConnectionStringRegistryKey" value="MuhtarConnStr" />
</appSettings>
<appDataConfiguration>
<ConnectionStringRegistryKeyPath value="SOFTWARE\ConnStr" />
</appDataConfiguration>
Windows
Registry’ içerisine aşağıdaki key/value değerlerini kayıt ediyoruz;
Registry Key name: "SOFTWARE\ConnStr”
path inin içinde “MuhtarConnStr"
Registry Local DB Decrypted Value : "Data
Source=XXXXXXX;Initial Catalog=XXXXXXX;integrated Security=true;"
Registry Local DB Encrypted Value : AAANA9ppHNzmLnkMrFQMwreKWcBFSTwc+LEB4bj9mnF9/pPwxupTkFjVh1472rxcCDPsda1Bt0tD2SGv8enHDobHghSErXy0MxhQfZEqjHnLjNv5Zn/aidLTW4cuaVSVgdls4x7Xg097Yz4QuL1nd7DUcfo=
Sonra,
Model classında, Identity Framework connection alma işleminin yapıldığı “ApplicationDbContext”
classının içerisinde, runtime da connection alma işleminin yapıldığı bölümde windows
registry den “MuhtarConnStr” connection string değerini aşağıdaki gibi alıp decrypt
ederek, DB connection işleminin güvenli ve sorunsuz olarak yapılabilmesini
sağlıyoruz;
namespace TalepBasvuru.Models
{
[Serializable]
public class ApplicationUser : IdentityUser { }
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public
ApplicationDbContext() : base()
{
var dataConfigurationSettings = EngineContext.Current.Resolve<IDataConfigurationSettings>();
string registryPath
= dataConfigurationSettings.ConnectionStringRegistryKeyPath;
var connectionStringRegistryKey
= ConfigurationManager.AppSettings["ConnectionStringRegistryKey"];
string connStr
= TalepBasvuruHelper.GetConnectionStringFromRegistry(registryPath, connectionStringRegistryKey);
if (string.IsNullOrEmpty(connStr)) {
StringBuilder errorMessage = new StringBuilder("Registry de
'");
errorMessage.Append(registryPath).Append(@"\").Append(connectionStringRegistryKey).Append("' keywordu
bulunamadi. Lütfen veritabani baglantisi icin connection string tanımlamasini
yapin!");
throw new NullReferenceException(errorMessage.ToString());
}
else
base.Database.Connection.ConnectionString = connStr;
}
}
}
Helper classında ki yardımcı
methodlar;
public static ICryptography Cryptography { get { return Context.Current.Resolve<ICryptography>(); } }
public static string GetConnectionStringFromRegistry(string pRegistryPath, string
pConnectionStringRegistryKey)
{
string connStr = null;
IDictionary<string, object> registryListItems =
GetValues(pRegistryPath);
if (registryListItems.ContainsKey(pConnectionStringRegistryKey))
{
string encryptedConnStr =
registryListItems[pConnectionStringRegistryKey] as string;
connStr =
Cryptography.Decrypt(encryptedConnStr);
}
return connStr;
}
private static Dictionary<string, object> GetValues(string pRegistryPath)
{
var values = new Dictionary<string, object>();
RegistryKey root = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine,RegistryView.Registry64);
root =
root.OpenSubKey(pRegistryPath);
if (root != null)
{
foreach (var value in root.GetValueNames())
{
try
{
values.Add(string.Format(value),
(root.GetValue(value).ToString() ?? ""));
}
catch (Exception)
{
…
}
}
return values;
}
return null;
}