.Net Core’da Encrypt & Decrypt İşlemleri ve Hash’den Farkı

Selamlar,

Bu makalede .Net Core Ortamında girilen bir datanın güvenliğini sağlamak için onu şifreliyeceğiz. Şifreleme, yani encryption bir string değeri gizlemek için bir takım methodlara başvurmaktır. Şifreleme işleminden sonra, en doğal hali ile datanın okunabilmesi için çözülmesi yani decrypt edilmesi gerekir. Her şifre kendine ait bir anahtar ile çözülür. Yani çift yönlü bir işlem yapılır. Kısaca, çok eski zamanlardan günümüze gelen şifreleme yöntemleri, bir bilgiyi taşırken o bilginin güvenle iletilmesini sağlar. Taşınan bu bilgi, iletilmesi gereken yere vardığında,  decrypt yani çözülerek asıl istenen bilgiye ulaşılır.

Biraz Tarihçe:

  • MÖ 1900 : Mısırlılar, kitabelerinde olağın dışı hiyeroglifler kullanmıştır. Bu kitabeler bilinen ilk yazılı kriptografik dökümanlardır.
  • MÖ 1500 : Mezopotamyada, Kriptografinin kayıtlara geçmiş ilk kullanımı sır niteliğinde saklanan bir formülün şifrelenmesi şeklinde karşımıza çıkmaktadır.
  • 2. Dünya savaşında Almanlar Arthur Scherbius tarafından icat edilmiş olan, o zamanın en gelişmiş makinası Enigmayı kullanıp gönderilen mesajları şifrelediler. Bu makine ile oluşturulan şifreli metinler Alan Turing ve ekibi tarafından çözüldü. Kapsamlı ilk bilgisayarın ortaya çıkışı da bu vesile ile gerçekleşmiş oldu:)

Ben de ilerki bir makalede size, kendi yazdığım şifreleme yöntemlerinden birini tanıtacağım :)

Şimdi gelin .Net Core ortamında örnek bir WebApi uygulaması oluşturalım. Ve bu şifreleme nasıl yapılıyor bir görelim.

ICipherService.cs : Bu interfacede Security sınıfında kullanılması zorunlu bırakılan, 2 method tanımlanacaktır. Encrypt() ve Decrypt().

Şifreleme amaçlı .Net Core’da kullanılan kütüphane “DataProtection“‘dır.

Security.cs:

  • “IDataProtectionProvider _dataProtectionProvider” : Encryption işlemleri için kullanılacak olan provider, burada tanımlanır.
  • “private const string Key = “cut-the-night-with-the-light” : Şifreleme işlemlerinde kullanılacak, sabit key’dir. İstenir ise bu da ayrıca farklı bir şekilde şifrelenerek saklanabilir.
  •  Security() : Constructor’da, yaratılırken kendisine gönderilen provider atanır.
  • Encrypt(string input): Gönderilen text’in şifrelenmesi sağlanır.
    • “var protector = _dataProtectionProvider.CreateProtector(Key)” : Tanımlanan sabit key’e göre DataProrectionProvider oluşturulur.
    • “return protector.Protect(input)” : İlgili text şifrelendikten sonra geri dönülür.
  • “Decrypt(string input)” : İlgili key’e göre şifrelenmiş içerik okunması amacı ile deşifre edilir.
    • “var protector = _dataProtectionProvider.CreateProtector(Key)” : Tanımlanan sabit key’e göre DataProrectionProvider yine burda da oluşturulur.
    • “return protector.Unprotect(input)” : Tekrardan orjinaline döndürülen text, geri dönülür.

Şimdi sıra geldi kullanım şekline: Aşağıdaki 2 kütüphanenin öncelikle eklenmesi gerekir.

SecurityController.cs:

  • “var SCollection = new ServiceCollection()”: Services Provider oluşturmak için collection yaratılır.
  • “SCollection.AddDataProtection(); var LockerKey = SCollection.BuildServiceProvider()” : İlgili services provider oluşturulur.
  • “var locker = ActivatorUtilities.CreateInstance<Security>(LockerKey)” : Önceden tanımladığımız “Security” sınıfının instance ilgili provider ile oluşturulur.
  •  “string encryptKey = locker.Encrypt(key)”: Düz text şifrelenir.
  • “string deencryptKey = locker.Decrypt(encryptKey)” : Şifreli text, tekrardan orijinal haline geri getirilir.

Örnek kullanım: Url üzerinden get edilen “DuruDondurmayıçokseviyor” yazısı, önce şifrelenerek sonra şifreli halinden tekrar eski haline, döndürülerek ekrana basılmıştır.

Ufuk Açma :) :

Bu örnekten de anlaşılacağı gibi Encryption şifrelendikten sonra tekrar okunması gereken datalar için kullanılmalıdır. Örneğin kullanıcının Vergi Numarası, TCKN numarası, IBAN numarası gibi. Burada sabit bir key üzerinden şifreleme işlemleri yapılabildiği gibi, farklı eko sistemlere WebServis hizmeti veren yapılarda, “HTTPS Authenticity”‘de olduğu gibi, benzer çözümlere ihtiyaç duyulabilir. Yani Private ve Public Key. Not: Şimdi okuyacaklarınız tamamen benim fikrim olup, sizin de kullanmanızdan ziyade feyz almanız amacı ile yazılmıştır. Örneğin birçok kuruluşa, WebServisi hizmeti veren bir yapı oluşturalım. Daha sonra sisteme login olan her kullanıcıya, kendi PrivateKey‘imizle şifrelediğimiz Public Encrypted bir key verelim. Ve bu kullanıcıya ait şifrelenmesini istediğimiz tüm veriler için,  bu PublicKey‘i talep edelim. Daha sonra kendi PrivateKey‘imiz ile, şifreli müşteriden aldığımız PublicKey’i decrypt edip, esas veriyi şifrelemek için kullanalım. İlerde, kullanıcı bu şifreli alanlara ait bilgileri okumak ister ise, bize gönderdiği PublicKey‘i kendi PrivateKey‘imiz ile decrypt edip, istenen dataları deşifre etmek için de kullanabiliriz.

Buradan ne çıkıyor ?

  • Tek bir key yerine, her bir client’a özel key oluşturulması.
  • Client’ı kendisine verilen key’in de okunabilir olmaması ve bize ait olan Private bir key ile şifrelenmesi.
  • Client’a özel her bir data’ya ait Encryption işleminde, client’dan alınan PublicKey’in Decrypt edilerek, DataProtectionProvider için gerekli key olarak kullanılması. “protector.Protect(PublicKey)” ile şifrelenmesi.
  • Client’a özel her bir data’ya ait Decryption işleminde, client’dan alınan PublicKey’in Decrypt edilerek, DataProtectionProvider için gerekli key olarak kullanılması. “protector.Unprotect(PublicKey)” ile deşifre edilmesi.

Bütün bu işlemlerdeki tek amaç, güvenliğin arttırılmasıdır. Client’ın kendisine verilen şifreli PublicKey’in, Database gibi kaybolmayacak sabit bir alanda tuttulması gerekmektedir. PublicKey’in kaybolması durumunda :), o kullanıcıya ait şifrelenen kayıtların okunması, maalesef imkansız bir hal alacaktır.

Şimdi sıra gelidi meşhur Hash Functionlar‘a.

Hash Functionlar: Şifreleme (Encryption)’dan farklı olarak MD5, SHA1, SHA2, BSD, CHECKSUM  gibi farklı isimler ile adlandırılabilen, geri dönüşü olmayan, yani tek yönlü çıktılar veren yapılardır. Asıl amacı, ilgili datanın bir yerden bir yere taşınması değil, eşlenik bir datanın orijinali ile aynı olduğuna dair bir onayın alınmasıdır. Örneğin Passwordler başka bir yerde okunmayan, sadece doğruluğu onaylanan alanlardır. Aynı Passwordler için, aynı Hash kodunun üretilmesi gerekmektedir. Hash kodların farklı olması durumunda, yanlış password’ün girildiği anlaşılır. “Hash” fonksiyonları güvenlikten ziyade, hız için yaratılmışlardır.

Oyunun Genel Kuralları:

  • Hash fonksiyonları çalıştıkları datanın büyüklüğünden bağımsız olarak, sabit bir boyutta çıktı üretirler.
  • Aynı data için her zaman aynı çıktı oluşur.
  • Farklı dataların çıktısı her zaman farklı olmalıdır.
    • Not: SHA-1 ve MD5’da, iki farklı data için aynı Hash’in üretildiği görülmüştür. Buna “Collision” denir ve büyük bir güvenlik açığıdır. Artık günümüzde SHA-1 ve MD5 büyük oranda geçerliliklerini yitirmişlerdir.

Hashler, güvenlik uygulamalarından başka data doğrulama amacı ile de bolca kullanılmaktadırlar. Örneğin önceden çalıştığım bir reklam ajansında, download edilecek videoların orijinallerinin hashleri’i alınıp, müşteriye dağıtılan örneklerin hashleri ile karşılaştırılırdı. Böylece müşteriye verilen videolarda herhangi bir bozukluğun olup olmadığına bakılırdı. Bu işlemin en büyük artısı, videoların boyutlarının çok büyük olmasından dolayı, orijinal datalar yerine, çok daha küçük olan hashleri ile karşılaştırmanın yapılması idi. Hash bir özüttür. Kısaca 2 büyük data yerine, 2 küçük datanın birbiri ile kıyaslanmasıdır. Çünkü aynı 2 data için aynı Hash’in üretilmesi gerekmektedir :) 

Hash’den, orijinal veriye geri dönülebilir mi? Her yerde hatta hocalarım dahil, %100 dönülemez dense de, Brute Force Attack denen bir yöntem vardır. Tüm kombinasyonların tek tek denenmesi ile sonuca ulaşılmaya çalışılan bir yöntemdir. SHA-1 veya MD5 ile Hashlenmiş, hangi function tipi ile Hashlendiği bilinen ve kullanılan salt key’in bilindiği durumlarda, orijinal dataya geri dönülme ihtimali az da olsa vardır. Bu nedenle seçilen şifrenin ve kullanılacak salt key’in uzunluğu, denenmesi gereken olasılık sayısını arttırmasından dolayı, önem arz etmektedir.

Blockchain ve Hashing :

Blockchain’inin ana güvenlik unsurlarından biri de Hashing işlemidir. Zincirdeki her bir blok, güvenik zincirinin bir halkasıdır. Bu yüzden, bu boğuma kadar olan  her bir işlem, eklenen yeni veriler ile birleştirilir. Kısaca alınacak result, bir blok zincirinin daha öncesinde meydana gelen işlemlerin bir bütünüdür. 

Bu nedenle halkaları oluşturan verilerden herhangi birinde, oluşacak basit bir değişiklik, çıktıda büyük bir farklılığa sebebiyet vermektedir.  Önceden blok zincirde olan herhangi bir kayıt değişikliği, tüm Hash değerlerini değiştirecek ve data tutarlılığını bozacaktır.

Bu düğümde kullanılan değerler ve diğer işlenen tüm datalar, bir sonraki bloğa Hash olarak aktarılır. Böylece her bir blok önceki bloğunu, ona gelen Hash değerini kullanarak doğruluyabilir. 

Geldik Hash ile ilgili .net Core örneğimize : Aşağıdaki komut ile.Net Core  Webapi projemiz yaratılır.

Aşağıdaki “KeyDerivation” kütüphanesi projeye eklenir.

Security.cs : 

HashCreate(string value, string salt): Hashlenecek Password ve dinamik olarak kullanılacak salt key parametre olarak verilir.

  • Pbkdf2: “Password-Based Key Derivation Function 2″ : PKCS # 5 v2.0 olan RSA Laboratuvarlarının Açık Anahtar Şifreleme Standartları (PKCS) serisinin bir parçasıdır. Yani kısaca, 5 parametre alan güvenliği arttırılmış bir şifreleme standartıdır.
    • password: Şifrelenecek düz text.
    • salt: Hashleme amaçlı kullanılacak key. Not: Bu örnekde, her bir request için fark bir salt key üretilmektedir.
    • prf: Özetleme fonksiyonu seçilir (SHA512)
    • iterationCount : İşlemin kaç kez tekrarlanacağı belirlenir. Ne kadar büyük olurlarsa, o kadar güvenlik artar. Ama bu durumda Hash değerinin oluşturulması, zaman alacaktır.
    • numBytesRequested: Oluşacak keyin uzunluğu burada tanımlanır.
  • “return System.Convert.ToBase64String(valueBytes) + “æ” + salt” : Her bir request’de, yeni bir salt key oluştuğu için, olusan Hash değere + salt key de eklenerek dönülür.

ValidateHash (): Doğrulama işleminin yapıldığı methoddur. Girilen password, önceden tanımlanan DB’deki Hashli password’e ait salt key ile tekrar Hashlenip, DB’deki password’ün Hash’li hali ile karşılaştırılır. Sonuca göre, girilen password’ün doğru olup olmadığı belirlenir.

  • value: Hashlenecek Password.
  • salt: Önceden Hashlemede kullanılan salt key.
  • hash: DB’de tutlan password’ün Hash’li hali.

HashCreate(): Her bir request için, dinamik olarak yeni bir salt keyin üretilmesi sağlanır.

SecurityController.cs: Deneme amaçlı örnek WebApi uygulaması.
  • “Security locker=new Security()” : Security sınıfının Instance’ı oluşturulur.
  • “string salt = locker.HashCreate()” : Yeni şifre yaratmak için, dinamik bir salt key üretilir.
  • “string encryptKey = locker.HashCreate(key, salt)” : WebApi ile parametre olarak alının password, yukarıda oluşturulan salt key ile Hashlenir. Örnek Hash aşağıdaki gibidir. Hem Hashlenen password hem de bu Hashlemede kullanılan salt key, aynı satıra “æ” işareti ile birbirinden ayrılarak konulmuştur.
  • “string getEncryptKey = encryptKey.Split(‘æ’)[0]” : “æ” parametresi ile password’ün Hash’li hali [0]’ıncı elemanı olarak alınır.
  • “string getSalt=encryptKey.Split(‘æ’)[1]” : Bu Hashlemede kullanılan salt key [1]. parametre olarak alınır.
  • “string result = locker.ValidateHash(key, getSalt, getEncryptKey).ToString()” : Yeni girilen Şifre, önceden şifrelemede kullanılan salt key ve son olarak, tanımlı şifrenin Hash’li hali parametre olarak ilgili methoda gönderilir. Burada girilen şifrenin doğruluğu kontrol edilir. Kısaca esas tanımlı şifrenin özeti, yeni girilen şifrenin özeti ile karşılaştırılır. Salt key, her Hashleme için farklı üretildiğinden, bu girişi yapılan kullanıcı şifresi, esas şifrenin Hashlenmesinde kullanılan salt key ile tekrar Hashlenir. Yani özeti alınır. Böylece doğrulu özetler üzerinden kontrol edilir. Not: Aynı data, aynı salt key için, kaç kere denenirse denensin, hep aynı özeti vermek zorundadır.

Örnek Url: 

Ekran:

Geldik bir makalenin daha sonuna. Bu makalede, Encryption ve Hashleme arasındaki farkları ve kullanım amaçlarını inceledik. Peki Client Side’dan, Server Side’a gönderilen önemli(şifrelenecek) datalar ne olacak? Aynı ağ üzerinde, trafiği dinleyen art niyetli kişiler tarafından kolayca ele geçirilebilecektir. Server side’da, şifrelemeden önce yani gönderme anında oluşan bu güvenlik açığını, mümkün olduğunca azaltmak başka bir makalenin konusu.

Yeni bir makalede görüşmek üzere hepinize hoşçakalın.

Source Code: https://github.com/borakasmer/Encryption

Source: 

Herkes Görsün:

Bunlar da hoşunuza gidebilir...

22 Cevaplar

  1. Tagi dedi ki:

    Konu güzel. Çok faydalı mekale teşekkürler..

  2. Furkan dedi ki:

    Emeğinize sağlık hocam yine çok faydalı olmuş

  3. Burak Karatatar dedi ki:

    Elinize sağlık hocam, güzel ve faydalı bir yazı daha :)

  4. Mert dedi ki:

    Senin gibi tutkulu, heyecanlı, meraklı, yaptığını sadece para kazanmak için yapmayan insanlara çooooook ihtiyaç var aağabey. Keşke üniversitelerde ders versen diyesim geliyor ama aman abi uzak dur. Memlekete, kendine, bizlere yazık etme.

    Eline, koluna, yüreğine sağlık.

    • borsoft dedi ki:

      Eyvallah Mert çok teşekkür ederim. Beni bildiğin mutlu ettin :)

      Aslında hep içimden hocalık geçiyor. Ama zor :)
      Hoşçakal..

  5. izzettin dedi ki:

    hocam elinize sağlık, her zamanki gibi muhteşemsiniz :) Acaba makalenin sonunda belirttiğiniz durum için de makaleniz mevcut mu? (client side’den server side’e önemli veri gönderme )

  6. musa dedi ki:

    Hocam Merhaba,

    Öncelikle teşekkür muteşem yazı için :) Ben .net core winform uygulaması oluşturdum. DataProtection ile istediğim text ‘i encrypt ediyorum. Farklı bir Web uygulamasında decrypt işlemi yapmak istediğim zaman “The Payload is invalid” hatası alıyorum. Bir uygulamada yaptığım enrypted string ‘ i başka bir uygulamada decrypt yapamıyorum. Bu konuda bilginiz var mı?

    • borsoft dedi ki:

      Selamlar Musa,
      Bir deli kuyuya taç atmış. 40 akıllı çıkaramamış :)
      Laravel yapar öyle şeyler :) Web’in PHP ise, .decodeURIComponent() gibi bir takım işler yapman gerekebilir..

  7. Selçuk dedi ki:

    Merhaba hocam, elinize sağlık

    Localde encrypt ettiğim veriyi sunucuda decrypt edemiyorum ya da tam tersi.
    Bu işlem sadece aynı makine üzerinde mi oluyor ?

  8. Murat dedi ki:

    Merhabalar

    Öncelikle paylaşımınız için teşekkürler.

    Tamamen bilmediğim ve merakımdan sorma gereği duydum;
    1- Salt ı dinamik olarak oluşturmak güvenliği arttırır mı? Mesala kullanıcı tablosundaki create date üzerinden salt oluşturmak gibi.
    Login valide ederken 2 defa tabloya gidilecek maalesef ama güvenlik için maaliyetine katlanılabilir mi?

    2- 32 yerine 256 / 8 , 16 yerine 128 / 8 yazmanın yardımı var mıdır?

    Teşekkürler

    • borsoft dedi ki:

      Selamlar,
      Salt’ı dinamik yaratmaktan ziyade her kullanıcı için ayrı tutmak güvenliği arttıracaktır. Ben olsam her salt için bir daha DB’ye gitmezdim.
      Saltı büyütmek Brute-force ataklara karşı daha güvenli olacaktır.

      İyi çalışmalar.

  9. Muhammet dedi ki:

    merhaba,
    ilk metodda şifreleme yaparken şifrelenmiş verinin uzunluğunu belirleyebilir miyiz ?

    • borsoft dedi ki:

      Selamlar,
      En sonunda trimleyerek belirleyebiliriz. Var olandan daha uzun yapmak ister isek de, 2 tane üretip onları Joinleyip gene trimleyebiliriz.

  10. Ümit dedi ki:

    Merhaba Hocam,

    Öncelikle elinize, emeğinize sağlık, Değerli vaktinizi ayırıp paylaşım yaptığınız için Teşekkürler. Sayenizde Makeleleri takip ederek bilgimize bilgi katıyoruz :)

    “Ufuk Açma : )” kısmı için bir sorum bulunmakta, Kullanıcı özelinde PublicKey oluşturduğumuzda bu key 90 gün(yada bu süre manuel belirlenebilir.) sonunda geri çözülemez hale gelmektedir ve çözüm olarak aşağıdaki makele kullanılması gerekmektedir.

    Siz olsanız bu noktada nasıl ilerlerdiniz ? 90 gün sonunda tüm kullanıcıların PublicKey’lerini yenileyerek mi çözerdiniz yoksa daha farklı bir düşünceniz varmıdır ?

    https://docs.microsoft.com/en-us/aspnet/core/security/data-protection/implementation/key-management?view=aspnetcore-5.0

    Şimdiden Teşekkürler.

  11. Abdullah dedi ki:

    Teşekkürler hocam faydalı bilgiler

Furkan için bir cevap yazın Cevabı iptal et

E-posta hesabınız yayımlanmayacak.