Neden Kullanırız?
T.C Kimlik No, Vergi Numarası, Telefon, IBAN No vb. alanları veri tabanımızda bir katman daha güvenli hale getirmek için kullanabiliriz. Burada dikkat edilmesi gereken durum, veri tabanı ve projeye erişimi olan insanlar tersine mühendislik ile proje içerisine gömülü olan şifreleme anahtarıyla şifreleri çözebilir. Bu şifre anahtarını böyle durumlarda canlı, geliştirme vb. ortamlara ait makine diskine veya windows kayıt defteri gibi yerlerde saklayabilirsiniz. Buradaki güvenlik yöntemini ihtiyaçlarınıza göre siz belirleyebiliriz.
Entit Framework Value Converter Nedir?
Entity Framework Değer dönüştürüceler ile veri tabanında okuma, yazma yaptığımızda verileri okuma, yazma için belirlediğimiz formatta otomatik olarak dönüştürmemize izin verir.
Örnek;
Bir kayıt eklediğimizde şifrelenecek alanları Entity Framework otomatik şifreler. Aynı şekilde veri tabanından okuma işlemi yaptığında şifreli alanları otomatik olarak çözer.
Kodlamaya Başlayalım
AesEncryptionExtension.cs dosyasını oluşturalım.
AES şifreleme algoritması performansı daha yüksek olduğu için kullanılmıştır. Dilerseniz başka bir şifreleme algoritması kullanabilirsiniz.
public static class AesEncryptionExtension
{
private static readonly SecureString _key = SecurityExtension.ConvertToSecureString("x7keXCkRFENWZ6jZ");
public static string Encrypt(string plainText)
{
if (plainText == null)
{
return null;
}
var bytesToBeEncrypted = Encoding.UTF8.GetBytes(plainText);
var passwordBytes = Encoding.UTF8.GetBytes(SecurityExtension.SecureStringToString(_key));
passwordBytes = SHA256.Create().ComputeHash(passwordBytes);
var bytesEncrypted = Encrypt(bytesToBeEncrypted, passwordBytes);
return Convert.ToBase64String(bytesEncrypted);
}
public static string Decrypt(string encryptedText)
{
if (encryptedText == null)
{
return null;
}
var bytesToBeDecrypted = Convert.FromBase64String(encryptedText);
var passwordBytes = Encoding.UTF8.GetBytes(SecurityExtension.SecureStringToString(_key));
passwordBytes = SHA256.Create().ComputeHash(passwordBytes);
var bytesDecrypted = Decrypt(bytesToBeDecrypted, passwordBytes);
return Encoding.UTF8.GetString(bytesDecrypted);
}
private static byte[] Encrypt(byte[] bytesToBeEncrypted, byte[] passwordBytes)
{
byte[] encryptedBytes = null;
var saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
using (MemoryStream ms = new MemoryStream())
{
using (RijndaelManaged AES = new RijndaelManaged())
{
var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
AES.KeySize = 256;
AES.BlockSize = 128;
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Mode = CipherMode.CBC;
using (var cs = new CryptoStream(ms, AES.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(bytesToBeEncrypted, 0, bytesToBeEncrypted.Length);
cs.Close();
}
encryptedBytes = ms.ToArray();
}
}
return encryptedBytes;
}
private static byte[] Decrypt(byte[] bytesToBeDecrypted, byte[] passwordBytes)
{
byte[] decryptedBytes = null;
var saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
using (MemoryStream ms = new MemoryStream())
{
using (RijndaelManaged AES = new RijndaelManaged())
{
var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
AES.KeySize = 256;
AES.BlockSize = 128;
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Mode = CipherMode.CBC;
using (var cs = new CryptoStream(ms, AES.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(bytesToBeDecrypted, 0, bytesToBeDecrypted.Length);
cs.Close();
}
decryptedBytes = ms.ToArray();
}
}
return decryptedBytes;
}
}
SecurityExtension.cs dosyasını oluşturalım.
Ben şifre anantarını uygulamanın içerisinde tutacağım. Yukarıda belirttiğim gibi size uygun olan saklama methodunu kullabilirsiniz. Şifre anahtarını SecureString ile 3. Şahısların memory'den erişmesini önlemek için kullanacağım.
public static class SecurityExtension
{
public static SecureString ConvertToSecureString(string password)
{
if (password == null)
{
throw new ArgumentNullException(nameof(password));
}
var securePassword = new SecureString();
foreach (char c in password)
{
securePassword.AppendChar(c);
}
securePassword.MakeReadOnly();
return securePassword;
}
public static String SecureStringToString(SecureString value)
{
IntPtr valuePtr = IntPtr.Zero;
try
{
valuePtr = Marshal.SecureStringToGlobalAllocUnicode(value);
return Marshal.PtrToStringUni(valuePtr);
}
finally
{
Marshal.ZeroFreeGlobalAllocUnicode(valuePtr);
}
}
}
DbContext.cs dosyamızı düzenleyelim.
public class ApplicationDbContext : IdentityDbContext
{
/// <summary>
/// Değer dönüştürücü değişkenimizi tanımlıyoruz.
/// </summary>
private readonly static ValueConverter<string,string> _encryptionValueConverter = new ValueConverter<string, string>(
v => AesEncryptionExtension.Encrypt(v),
v => AesEncryptionExtension.Decrypt(v));
public DbSet<Person> Persons { get; set; }
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
//Veri tabanında şifrelenecek kolonları belirtiyoruz.
builder.Entity<Person>().Property(p => p.Identity).HasConversion(_encryptionValueConverter);
builder.Entity<Person>().Property(p => p.PhoneNumber).HasConversion(_encryptionValueConverter);
//Veri tabanına örnek bir kayıt atıyoruz.
builder.Entity<Person>().HasData(
new Person() { Id = Guid.NewGuid(), Identity = "8248649570", FirstName = "Ayaz", LastName = "Duru", PhoneNumber = "5554442121" });
}
}
Sonuç
Veri tabanında ki kayıtların görünümü:

Veritabanından _applicationDbContext.Persons.ToList() olarak getirdiğimiz zaman:

Örnek projeyi github üzerinden indirmek veya görüntülemek için https://github.com/ayzdru/AspNetEntityFrameworkDataEncryption adresine gidebilirsiniz.
Görüşmek Dileğiyle...
İyi çalışmalar..