Veritabanında Nasıl Şifre Saklamalıyız – Hashing ve Salting

Standard

Merhabalar. Bu sefer biraz değişiklik yaparak kodu az, konusu bol, eğlenceli bir yazı yazmaya karar verdim. 🙂

Veritabanı bir yazılım veya bilgisayar mühendisinin öğrendiği en temel konulardandır, ama üniversitelerde verilen veritabanı derslerinde konunun her zaman için teorik kısmı ele alınır. Bu derslerde biz functional dependency’den girip 3NF – 4NF’ten çıkaduralım, pratik bilgi olmadan teorik bilginin pek de faydalı olmadığını ancak mezun olduktan sonra görebiliyoruz. Ki bu durum bile eğer ders doğru işleniyorsa geçerli; bende olduğu gibi grammar nazi hocanızdan bütün dönem boyunca yalnızca “tuition fee”nin ne demek olduğunu öğrenerek dersi geçiyorsanız durum daha da kötüleşiyor. 🙂

Fakat kullanıcı adının “Login” olması?

Bu eksik pratik bilgilerin en basit ve önemlilerinden biri ise, veritabanında şifrelerin nasıl saklanacağı. Bir veritabanı hacklendiğinde ilk hedef şifrelerdir ve açığa çıkmaları direk o sistemin çökmesine sebep olur, çünkü veritabanını hackleyen kişi istediği kullanıcının hesabına girerek hem bilgi çalabilir, hem de maddi – manevi zarara neden olabilir. Eğer internette kısa bir araştırma yaparsanız en büyük firmaların bile veritabanlarının hacklendiği haberlerine ulaşabilirsiniz, bkz. Adobe, Sony, Valve (Steam). Ki düşünün, eğer Valve veritabanındaki şifreleri doğru saklamayı bilmeseydi Steam’deki tüm hesaplar açığa çıkardı ve insanlar para vererek aldıkları oyunlarını kaybederdi (kredi kartı bilgileri kısmına girmiyorum bile).

Veritabanında şifre saklarken, yukarıda bahsettiğim pratik bilgi eksikliğine sahip olan bir mühendisin yapıp yapabileceği en büyük hata ise şifreleri plain text olarak (yani olduğu gibi) saklamaktır. Ya yanlış olduğu bilinmediği için, ya da “amaan yaa bir şey olmaz” diyerek (Türk mantığı :)) yapılan bu hata, aşağıdaki gibi doldurulmuş bir veritabanı ile karşılaştığında bir hackerın ağır alay konusu olmanıza sebep olabilir:

Peki hackerların gizli gizli Justin Bieber’ı sevdiğimizi öğrenmemeleri (ve kullanıcılarımızın hesaplarını ele geçirmemeleri) için ne yapmalıyız?

Cevap: Veritabanında asla şifre tutmamalıyız.

Uzun cevap: Şifrelerimizi hashleyerek, veritabanında bu hashleri tutmalıyız. Sisteme giriş yapılırken şifrenin doğru olup olmadığını kontrol etmek için ise, kullanıcının girdiği şifreyi de hashleyerek bu hashlerin aynı olup olmadığına bakmalıyız.

Açıklamaya hashin ne olduğu ile başlayalım. Hash, bir anahtar değere belirli bir hash fonksiyonu ile işlem yapılması ile oluşan sabit uzunluktaki veridir. Daha pratik anlatmak gerekirse, elimizdeki veriyi bir nevi şifreleme algoritmasından geçirdikten sonra elimize geçen değerdir. Örneğin, “merhaba” kelimesinin SHA256 ile alınan hashi “4c6bcdd55f3153e1939669ab1ec039e4059174dc25abdfcb2f58868849b4d61b” döndürür.

Hashlerin aşağıdaki özellikleri bizim için kullanışlı olmalarını sağlar:

1) İki ayrı anahtarın hashlerinin aynı olma olasılığı yok sayılacak kadar düşüktür. Yani, “merhaba” kelimesinin sonucunda gördüğünüz yukarıdaki hash, “merhaba” kelimesi dışında elde edilemez sayılır.

2) Hash fonksiyonuna verilen değerde yapılan küçük bir değişiklik, hashte büyük değişikliklere neden olur.
“merhaba1” => “4a1ab980c9dc9ff1bbb986f9b8e5211b785a9e0d915c2b2cea1792796404ccd0”
“merhaba2” => “01f8da42a5991050b46c7ecd145a8b9c22a8cda9cd5736c581f1c7cd81fade79”

3) Hashler tek yönlüdür. Bir hashten onun anahtar değerine ulaşamazsınız. Yani yukarıdaki değerleri bilsek bile onların “merhaba1” ya da “merhaba2″den geldiklerini öğrenemeyiz.

Eğer şifrelerimizi bu şekilde hash haline getirip, bu hashleri veritabanında tutarsak, sistemimizi daha güvenli hale getiririz. Tek yapmamız gereken yukarıda bahsettiğim gibi kullanıcı şifresini girdiğinde bunu da aynı algoritma ile hash haline getirerek iki hashi karşılaştırıp doğru olup olmadıklarına bakmak. Ufak bir not olarak, hashler bu özellikleri nedeniyle indirilen dosyaların doğru inip inmediğini kontrol etmek gibi başka amaçlarla da kullanılıyor.

Peki, artık şifrelerimizi olduğu gibi tutmadığımıza göre, veritabanımız güvenli, değil mi?

Şifrelerimizi hashleyerek veritabanında saklamak hackerların işini zorlaştırarak bize bir derece güvenlik verse de, şifreleri sadece hashleyerek bıraktığımızda hala ele geçirilmelerine imkan verebilecek, adına rainbow attack (gökküşağı saldırısı) denilen bir saldırıya karşı savunmasız oluruz.

Gökkuşağı saldırısı denince akla gelenler.

Gökkuşağı saldırısında hacker, adına gökkuşağı tablosu (rainbow table) denilen bir tablo oluşturur. Bu tablo, şifre olabilecek belirli metinlerin veritabanımızın kullandığı hashing fonksiyonu ile oluşturulmuş hashlerinin tutulduğu bir tablodur. Örneğin, “aaaaaaa”dan başlayarak “zzzzzzz”ye kadar giden bütün olası kombinasyonların hashlerinin bulunduğu tablo, ardından veritabanına karşı sırayla sorgulanarak aradan aynı olan hashlerin olup olmadığına bakılır. Ki bu örnekte, nihayetinde sıra “merhaba”ya karşılık gelen hashe geldiğinde hacker o hashin hangi kullanıcının şifresine denk geldiğini öğrenir ve bu sayede şifreyi de öğrenerek kullanıcının hesabını ele geçirir. Bu uzun bir işlem gibi gözükse de, bu sorgulama işlemi kabul edilebilir sürede tamamlanabilir (örneğin 1-2 hafta). Ayrıca tek sorguda tüm veritabanını tarama imkanı verdiği için kullanıcıların şifrelerini ortaya çıkarma olasılığı yüksek olan (ve önüne geçmemiz gereken) bir saldırıdır. Bunun içinse, ikinci konumuz olan salting (yani tuzlama) devreye giriyor.

İşkembe çorbasında işkembenin iri kıyılması ile elde edilen “Tuzlama”nın maalesef konumuzla bir ilgisi yok.

Salt, verinin kendine özel bir değeridir, örn. bir kullanıcının kullanıcı adı (eğer aynı kullanıcı adı tekrar kullanılamıyorsa). Salting ise, bir veriyi hashlerken bu Salt değerini verinin başına ya da sonuna ekleyerek hash oluşturma işlemini bu şekilde gerçekleştirmektir. Aşağıdaki şekilde daha net olarak anlatabiliriz:

SaltedHash = hashfunc(password+salt)
ya da
SaltedHash = hashfunc(hashfunc(password)+salt)

Daha belirgin hale getirmek için, ilk verdiğim örneğe bakarsak, kullanıcı adının “encephalon”, şifrenin de “ilovejustinbieber” olduğu yerde “ilovejustinbieberencephalon” değerinin hashini almalıyız (ya da “ilovejustinbieber” hashini aldıktan sonra, o değerin sonuna “encephalon” ekleyerek tekrar hash almalıyız).

Bu yaptığımız ufak eklenti, aşağıdaki avantajları sağlıyor:

1) Şifrenin uzunluğunu ve karmaşıklığını arttırıyor. Bu sayede hem brute force, hem de rainbow attack saldırılarına karşı savunmamız artıyor.

2) Hacker salt olarak ne kullandığımızı bulsa bile, her kullanıcı için tek tek rainbow table üretmesi gerekiyor ve bu yöntemle bir seferde yalnızca tek bir kullanıcının şifresini sorgulayabiliyor. Salting yapmadan önce tek sorguda tüm kullanıcıların şifresini kontrol edebiliyordu.

3) Şifresi aynı olan kişilerin bile veritabanında kayıtlı hash değerleri farklı oluyor.

Son olarak da, bu hashing ve salting işlemini Silverlight ve Windows 8 uygulamalarında nasıl yapabileceğimize dair kodları sağlıyorum.

Silverlight:

using System.Text;
using System.Security.Cryptography;
                byte[] data = UTF8Encoding.UTF8.GetBytes(password + username);
                SHA256Managed sha = new SHA256Managed();
                byte[] result = sha.ComputeHash(data);
                StringBuilder output = new StringBuilder("");
                for (int i = 0; i < result.Length; i++)
                {
                    output.Append(result[i].ToString("X2"));
                }
                string resultString = output.ToString();

Windows 8:

using Windows.Security.Cryptography.Core;
using Windows.Storage.Streams;
                        HashAlgorithmProvider algorithm = HashAlgorithmProvider.OpenAlgorithm("SHA256");
                        IBuffer vector = CryptographicBuffer.ConvertStringToBinary(password + username, BinaryStringEncoding.Utf8);
                        IBuffer digest = algorithm.HashData(vector);
                        string resultString = CryptographicBuffer.EncodeToHexString(digest);

Yazımı bitirmeden önce belirtmeliyim ki, bu işlem düşük ve orta güvenlik seviyeli sistemlere uygun. Brute force ve rainbow attack dışında yapılabilecek daha pek çok farklı saldırı türü mevcut; finansal işlemler yapan ve / veya yüksek güvenlik gerektiren uygulamalarda daha ileri güvenlik önlemleri gerekebilir.

Eğer yazıyı baştan sonra okuyarak buraya kadar geldiyseniz, teşekkür ediyorum. 🙂 Gelecek yazılarımda görüşmek üzere.

Dipnot 1: Tuition fee’nin kelime anlamı öğrenim ücreti / harç bedeli.
Dipnot 2: Justin Bieber’ı hiç sevmem. Hem de hiç.
Dipnot 3: Yazılım ile ilgili bir blog içinde tek yazıda Justin Bieber, gökkuşakları, unicorn ve işkembe çorbasından bahsettim. Güzel oldu.

Advertisements

6 thoughts on “Veritabanında Nasıl Şifre Saklamalıyız – Hashing ve Salting

  1. Meltem

    Gerçekten eğlenceli ve bir o kadar da öğretici bir yazı olmuş. Bitirme projemde işime yarayacak bir konuydu. Emeğinize sağlık. Başarılarınızın devamını dilerim..

Comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s