.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: 

Herkes Görsün:

Bunlar da hoşunuza gidebilir...

6 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 :)

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir