Trochu self-promo, ale…
Počas prvej vlny pandemických dobrovoľníckych projektov som si všimol, že mnohí skladujú rodné čísla a zdravotné záznamy len tak. Bonusom bola autentifikácia, kde sa s frontednu posielal hash hesla, ktorý sa porovnával priamo v databáze.
Veľmi dlho sa mi páči myšlienka Always Encrypted v MS SQL. Táto funkcionalita umožňuje mať v databáze zašifrované dáta tak, že ich nevidí ani databázový administrátor ani nik okoloidúci, lebo si ich rozšifruje priamo aplikácia cez MS SQL klienta. No daná technológia nie je ľahko použiteľná v prípade, že ako zdroj šifrovacích kľúčov je niečo iné ako Azure Key Valut, alebo certifikát vo Windows store.
Po narazení na blog Jiřího Činčuri som začal pracovať na knižnici, ktorá pridá funkcionalitu „Alwais encrypted“ priamo do Entity Frameworkového modelu modelu – Harrison314.EntityFrameworkCore.Encryption.
Táto knižnica je postavená na EF Value konvertoroch, takže šifrovanie je s pohľadu aplikácie transparentné. No prácu so zašifrovanými stĺpcami je možná len v „encryption scope“ (v podstate sa tak označia časti programu, ktoré majú prístup k šifrovaným dátam).
Kľúčové vlastnosti:
- Databázovo agnostický
- Inšpirované MS SQL Always Encrypted (obdobná kryptografia, algoritmy, deterministické a randomizované šifrovanie riadkov v tabuľke,…)
- Podpora kompresie dát
- KillSwitch (Encryption provider vie signalizovať, že treba okamžite zmazať šifrovacie kľúče z pamäte a vypnúť aplikáciu)
- Rôzny provideri pre šifrovanie databázového master kľúča:
- Heslo
- Certifikát v store
- Čipová karta (dá sa zlomiť, keď na dvere zaklopú kukláči), HSM
- DPAPI
- Vlastné provideri, sieťový provideri,…
Malá ukážka kódu:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Patient>(p =>
{
p.HasKey(t => t.Id);
p.Property(t => t.FirstName).IsRequired().HasMaxLength(150);
p.Property(t => t.LastName).IsRequired().HasMaxLength(150);
p.Property(t => t.SocialSecurityNumber).IsRequired().HasMaxLength(150);
// ...
});
modelBuilder.Entity<Visist>(p =>
{
p.HasKey(t => t.Id);
});
}
Pre použitie šifrovaných stĺpcov v tabuľke stačí priďať:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.AddEncryptionContext();
modelBuilder.Entity<Patient>(p =>
{
p.HasKey(t => t.Id);
p.Property(t => t.FirstName)
.HasEncrypted("Patient.FirstName",
EncrypetionType.AEAD_AES_256_CBC_HMAC_SHA_256,
EncryptionMode.Randomized,
CompressionMode.None)
.IsRequired().HasMaxLength(150);
p.Property(t => t.LastName)
.HasEncrypted("Patient.LastName",
EncrypetionType.AEAD_AES_256_CBC_HMAC_SHA_256,
EncryptionMode.Randomized,
CompressionMode.None)
.IsRequired().HasMaxLength(150);
p.Property(t => t.SocialSecurityNumber)
.HasEncrypted("Patient.SocialSecurityNumber",
EncrypetionType.AEAD_AES_256_CBC_HMAC_SHA_256,
EncryptionMode.Deterministic,
CompressionMode.None)
.IsRequired().HasMaxLength(150);
// ...
});
modelBuilder.Entity<Visist>(p =>
{
p.HasKey(t => t.Id);
});
}
Plus registrovať služby a šifrovacieho providera v IoC kontaineri.
Viac informácii a ukážky kódu sú na githubej stránke projektu https://github.com/harrison314/Harrison314.EntityFrameworkCore.Encryption.