Derinlemesine yazılım eğitimleri için kanalımı takip edebilirsiniz...

C#’ta SecureString Sınıfı İle Memory Güvenliği

Merhaba,

Üzerinde çalıştığınız projede kâh kullanıcılar için kâh yazılım için önem arz eden kritik bilgiler üzerinde çalışıyor olabilirsiniz. Bu bilgiler kullanıcılara binaen kimlik yahut kredi kartı bilgileri olabilecekken, yazılıma dair bağlantı, port veya herhangi bir devlet sırrı olabilir. Çoğu yazılımcı bu tarz bilgileri String ifadeler olarak tutmakta ve üzerinde çalışmaktadır. Teknik olarak uygulamada kullanılan değişkenler memory üzerinde tutulacağı için ve 2. ya da 3. şahıslar tarafından memorye ulaşılıp sistem üzerinde dönen tüm verilerin içeriklerinde gözlem yapabilme ihtimalleri olduğu için bizlerin bu değişkenleri güvenli bir şekilde şifrelememiz ve korumamız gerekmektedir.

Konumuzu memory üzerinde biraz daha detaya inerek geliştirelim. Mevcut uygulamamızın işleyişi sırasında memory’de tutulan verilerin yerleri değişebilme ihtimaliyle beraber, bir kopyasının daha oluşturulabilme ihtimalide mevcuttur. Ee haliyle bu gibi bir durumda memory’de bulunan değişkenimizden birden fazla yerde olma ihtimali mevcuttur. İşte bu ihtimal kritik bilgilerin memory de 2. ya da 3. şahıslar tarafından ele geçirilme ihtimalini yükseltmekte ve biz yazılımcılara büyük görev ve sorumluluk yüklemektedir.

Yukarıda da bahsettiğim gibi kritik bilgiler genellikle kompleks yahut metinsel olduklarından dolayı bir çok yerde String ifadeler eşliğinde tutulmaktadır. Peki String ifadelerin memory yapılanmasındaki işlevsel özellikleri nelerdir? diye sorma ihtimalinize nazaran birazda bu konuya açıklık getirmekte fayda var.

String ifadeler immutable(sabit/kesin/değişmez) yapılardır. Yani string bir ifade üzerinde yapılan herhangi bir işlem(ekleme, çıkarma, değiştirme vs.) direkt olarak değişkenin bellekteki fiziksel yapısına yansıtılmamakta, ilgili değişkenin bir kopyası oluşturularak yapılan yeniliklerin o kopya üzerine gerçekleştirilmesini sağlamaktadır. Bu işlem, eski değişkenin olduğu gibi hafızadaki ilgili adreste kaldığı anlamına gelmektedir.

Yani uzun lafın kısası, bizler elimizdeki kritik bilgileri tuttuğumuz değişkenler üzerinde ne yaparsak yapalım bu bilgilerin orjinal hallerine hafıza üzerinden erişilebilme ihtimali her daim olacaktır. Ta ki SecureString sınıfı ile çalışmamızı gerçekleştirene kadar…

SecureString sınıfı ile müdahale ettiğimiz değişkenlerin bellek üzerinde DPAPI (Data Protection API) ile şifreli bir şekilde tutulmasını sağlamaktayız. Ayrıca değişken değerinde yapılan herhangi bir işlemi değişkenin kopyasını oluşturmadan, direkt olarak bellekteki fiziksel değişkene yansıtacaktır.

Şimdi aşağıdaki örnek kod bloğunu inceleyiniz.

            string KrediKartiNo = "1234123412341234";
            SecureString secure = new SecureString();
            KrediKartiNo.ToCharArray().ToList().ForEach(c => secure.AppendChar(c));
            secure.MakeReadOnly();

Yukarıdaki kod bloğunu incelerseniz eğer SecureString sınıfı ile kritik bilgi taşıdığını varsaydığımız KrediKartiNo isimli değişkeni koruma altına almaktayız. Tabi bu işlem için kritik bilgi bir karakter dizisine çevrildikten sonra AppendChar metodu ile tek tek karakterleri ilgili SecureString nesnesine iliştirilmektedir. Son olarak MakeReadOnly metodu ile string değişkenimizi herhangi bir işleve karşı immutable yapıyoruz.

Burada vurgulamak istediğim bir nokta vardır ki o da, yapmış olduğumuz işlemin KrediKartiNo isimli değişkeni şifreli bir şekilde elde etmek olmadığıdır. Burada ki niyet bellekte ilgili bilgiye kötü niyetli kişilerin erişimini engellemek için bellekteki fiziksel değişkene bir koruma oluşturmuş olduk. Bilakis değişkenin değerine erişmek istediğimizde direkt olarak ne ise o şekilde elde edilecektir.

SecureString sınıfı ile koruma altına alınan değişkenlerin verilerini çalışma zamanı(run time) sürecinde aşağıdaki gibi birden fazla yolla elde edebiliriz.

1. Yol

            string KrediKartiNo = "1234123412341234";
            SecureString secure = new SecureString();
            KrediKartiNo.ToCharArray().ToList().ForEach(c => secure.AppendChar(c));
            secure.MakeReadOnly();

            IntPtr x = Marshal.SecureStringToBSTR(secure);
            string Deger = Marshal.PtrToStringUni(x);

2. Yol

            string KrediKartiNo = "1234123412341234";
            SecureString secure = new SecureString();
            KrediKartiNo.ToCharArray().ToList().ForEach(c => secure.AppendChar(c));
            secure.MakeReadOnly();

            IntPtr x = Marshal.SecureStringToBSTR(secure);
            string Deger = Marshal.PtrToStringAuto(x);

Dikkat ederseniz vermiş olduğum bu ilk iki yolda Marshal sınıfının static elemanlarından olan SecureStringToBSTR metodu aracılığıyla ilgili SecureString nesnesindeki değişkenin değeri memoryden okunmakta ve IntPtr tipinden bir nesne olarak elde edilmektedir. Ve tekrardan bu IntPtr nesnesi Marshal sınıfının static olan PtrToStringUni, PtrToStringAuto vs. gibi metotları aracılığıyla işlenerek değeri stringe çevrilerek elde edilmektedir.

3. Yol

            string KrediKartiNo = "1234123412341234";
            SecureString secure = new SecureString();
            KrediKartiNo.ToCharArray().ToList().ForEach(c => secure.AppendChar(c));
            secure.MakeReadOnly();

            IntPtr x = Marshal.SecureStringToBSTR(secure);

            char[] topla = new char[secure.Length];
            Marshal.Copy(x, topla, 0, secure.Length);
            string Deger = string.Join("", topla);
            Marshal.ZeroFreeBSTR(x);

Bu 3. yolda ise Unmanaged Code(Yönetilmeyen Kod) ve CLR dışı alanlara bulaşmış olduk.

Son olarak SecureString sınıfı ile korumaya alacağımız her değişkene özel bu çalışmayı tek tek yapmaktansa aşağıdaki gibi bir Extension metot ile bu işlemi tek seferde gerçekleştirebiliriz.

    static class Extension
    {
        public static SecureString Protect(this string x)
        {
            SecureString secure = new SecureString();
            x.ToCharArray().ToList().ForEach(c => secure.AppendChar(c));
            secure.MakeReadOnly();
            return secure;
        }
    }

Günümüzde bilgi her ne kadar güç olsada, bilgiyi koruyabilmek gücün iki katıdır. O yüzden bu tarz durumları her daim göz önünde bulundurarak çalışmalarımızda titiz davranmaya özen göstermeliyiz.

Sonraki yazılarımda görüşmek üzere…
İyi çalışmalar dilerim…

Bunlar da hoşunuza gidebilir...

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir