Bir uygulama geliÅŸtirirken göz önünde bulundurmamız gereken önemli konulardan biri de hiç şüphesiz “güvenlik”tir. Güvenlik konusu deyince nedense aklımıza daha çok network tabanlı bir koruma gelir. Oysa birçok saldırının kaynağı uygulama içerisindeki açıklardan kaynaklanmaktadır. Bir uygulamayı güvenli kılmanın birçok yöntemi bulunmaktadır. Hakların düzenlenmesi, doÄŸru ayarların yapılması, kullanıcıdan gelen bilgilerin doÄŸrulanması, etkili validation iÅŸlemlerinin yapılması, gizli-kritik bilgilerin uygulama içerisinde saklanmaması, etkin hata yönetiminin saÄŸlanması, aktif bir test gerçekleÅŸtirilmesi, veritabanının koruma altına alınması, .NET platformunda unmanaged kaynaklarının doÄŸru yönetilmesi bu yöntemlerden sadece bir kaçı. Bu yazıda uygulama güvenliÄŸini saÄŸlayan yöntemlerden biri olan ve Windows iÅŸletim sisteminin 2000 ve sonraki sürümleri tarafından desteklenen DPAPI (Data Protection Application Programming Interface) arabiriminin .NET cephesi hakkında konuÅŸacağız.
Data koruma aracı olan Data Protection API , Triple-DES algoritmasını kullanarak verileri kiÅŸi ve makine bazlı encrypt ve decrypt iÅŸlemini saÄŸlar. Bu API’nin çalışma mantığı ve iÅŸlevi ile ilgili ayrıntılı bilgiyi MSDN ‘de bulabilirsiniz.DPAPI, temelde CryptProtectData ve CryptUnprotectData fonksiyonlarına sahiptir. .NET teknolojisi, güvenlikle ilgili uygulama ve sistem bazlı System.Security altında bulunan birçok sınıf içermektedir. Bu kütüphane altındaki nesneleri verileri ÅŸifrelerken DPAPI birimini kullanır. Daha önceki versiyonlarda tipi API çağırma mantığıyla bu iÅŸlem yapılırdı. Fakat 2.0 ile birlikte doÄŸrudan System.Security.Cryptography altında bulunan ProtectedData sınıfı bu arabirimini wrap etmiÅŸtir. ProtectedData classı, Protect() ve Unprotect() isminde iki static fonskiyon içermektedir. public static byte[ ] Protect(byte[ ] userData, byte[ ] optionalEntropy, System.Security.Cryptography.DataProtectionScope scope)
public static byte[ ] Unprotect(byte[ ] encryptedData, byte[ ] optionalEntropy, System.Security.Cryptography.DataProtectionScope scope)Uygulamalarımızda Data Protection API için wrapper yazmak yerine .NET 2.0′in ProtectedData sınıfını kullanmamız daha kolay olacaktır. Uygulamalarda en çok ÅŸifrelenen bilgilerden biri Connection String bilgisidir. Uygulamamızın beslendiÄŸi veritabanının güvenlik bilgilerinin bulunduÄŸu bu cümleyi ÅŸifreli halde saklamamız baÅŸkası tarafından ilk bakışta okunması engellemiÅŸ olur. AÅŸağıdaki örnekte Server=AKAYMAZ\AKAYMAZ;Database=Csharp;uid=sa;pwd=sa olarak tutulan connection string deÄŸeri, encrypt ve decrypt edilmiÅŸtir. Protect() ve Unprotect() metodlarında deÄŸerleri kullanıcı veya makine bazında ÅŸifreleyip çözebildiÄŸimiz gibi her kullanıcını bu deÄŸeri çözmemesi için de bir anahtar(entropy) oluÅŸturulur. ÅžifrelenmiÅŸ deÄŸeri çözerken kullanıcıdan bu anahtar istenilebilir.
using System;
using System.Security.Cryptography;
using System.Text;
class Program
{
static void Main()
{
string EntropyStr = "AhmetKaymaz";
string CnnStr = @"Server=AKAYMAZ\AKAYMAZ;Database=DB;uid=;pwd=";
//Stringleri byte dizilere çevirelim
byte[] EntropyArr = Encoding.Unicode.GetBytes(EntropyStr);
byte[] CnnArr = Encoding.Unicode.GetBytes(CnnStr);
//Bilgiyi encrypt edelim
byte[] EncryptedArr = ProtectedData.Protect(CnnArr, EntropyArr, DataProtectionScope.CurrentUser);
//Byte türündeki bu diziyi ekrana yazdıralım.
//PrintBytes(EncryptedArr);
//Encode edilmiş datayı decrypt edelim
byte[] DecryptedArr = ProtectedData.Unprotect(EncryptedArr, EntropyArr, DataProtectionScope.CurrentUser);
Console.WriteLine(Encoding.Unicode.GetString(DecryptedArr));
Console.ReadLine();
}//Main
//Byte türündeki diziyi yazdırma metodu
static void PrintBytes(byte[] bytes)
{
foreach (byte b in bytes)
{
Console.Write("{0:x2}, ", b);
}
}//PrintBytes
}//Program
Imports System
Imports System.Security.Cryptography
Imports System.Text
Module Module1
Sub Main()
'GetPassword();
Dim EntropyStr As String = "AhmetKaymaz"
Dim CnnStr As String = "Server=AKAYMAZ\AKAYMAZ;Database=DB;uid=;pwd="
'Stringleri byte dizilere çevirelim
Dim EntropyArr As Byte() = Encoding.Unicode.GetBytes(EntropyStr)
Dim CnnArr As Byte() = Encoding.Unicode.GetBytes(CnnStr)
'Bilgiyi encrypt edelim
Dim EncryptedArr As Byte() = ProtectedData.Protect(CnnArr, EntropyArr, DataProtectionScope.CurrentUser)
'Byte türündeki bu diziyi ekrana yazdıralım.
PrintBytes(EncryptedArr)
'Encode edilmiş datayı decrypt edelim
Dim DecryptedArr As Byte() = ProtectedData.Unprotect(EncryptedArr, EntropyArr, DataProtectionScope.CurrentUser)
Console.WriteLine(Encoding.Unicode.GetString(DecryptedArr))
Console.ReadLine()
End Sub
'Byte türündeki diziyi yazdırma metodu
Private Sub PrintBytes(ByVal bytes As Byte())
For Each b As Byte In bytes
Console.Write("{0:x2}, ", b)
Next
End Sub
End Module
System.Security.SecureString Class
.NET 2.0 ile birlikte gelmiÅŸ ve uygulama güvenliÄŸini saÄŸlayan önemli classlardan biri de SecureString sınıfıdır. BilindiÄŸi gibi bazı deÄŸerleri anlık olarak tutmak için deÄŸiÅŸkenleri kullanırız. DeÄŸiÅŸkenler de memory üzerinde tutulur. CLR, Garbage Collector mekanizmasını kullanarak memory üzerinde tutulan bu deÄŸerlerin yerlerini deÄŸiÅŸtirebilir bu konum deÄŸiÅŸimi sırasında deÄŸiÅŸkenlerin hafıza üzerinde birden fazla kopyası oluÅŸabilir. Ayrıca bu deÄŸerler, memory üzerinde encrypt edilmedikleri için bir baÅŸkası uygulamamızın çalıştığı process’e ait memory alanını tarayıp bu bilgiye ulaÅŸabilir. Ayrıca string veri türünün, “immutable” karakterinde olması da bir güvenlik açığıydı.. Yani string deÄŸiÅŸkeninin deÄŸerini deÄŸiÅŸtirmek istediÄŸimizde doÄŸrudan eski deÄŸer üzerine yazmak yerine yeni konumlu bir deÄŸiÅŸken tanımlar. Bu sorunları çözmek için .NET 2.0, etkileyici bir özellik olan SecureString sınıfını sunmaktadır. Bu sınıf türünde tanımladığımız deÄŸerler DPAPI ( Data Protection API) tarafından memory üzerinde encrypt edilmiÅŸ olarak saklanır. Bu durumda deÄŸiÅŸkenin, memory üzerindeki konumu deÄŸiÅŸmez(pinned in memory) ve hiç bir zaman memory üzerinde birden fazla kopyası bulunmaz. Connection string veya kredi kartı gibi bilgileri bu sınıf türünde tanımlayabiliriz. DeÄŸeri memoryye yüklerken bu sınıfın char türünde deÄŸer alan AppendChar() metodu kullanılır. SecureString türünde memory üzerinde tutulan deÄŸeri okumak için System.Runtime.InteropServices.Marshal.SecureStringToBSTR() metodu kullanılır.
using System;
using System.Security;
using System.Runtime.InteropServices;
//. . . ..
SecureString SecStr = new SecureString();
//Değeri AHMET olan şifreyi hafızaya atalım
SecStr.AppendChar('A');
SecStr.AppendChar('H');
SecStr.AppendChar('M');
SecStr.AppendChar('E');
SecStr.AppendChar('T');
IntPtr Ptr = Marshal.SecureStringToBSTR(SecStr);
string Str = Marshal.PtrToStringUni(Ptr);
Console.WriteLine(Str);
Dim SecStr As New SecureString()
'Değeri AHMET olan şifreyi hafızaya atalım
SecStr.AppendChar("A")
SecStr.AppendChar("H")
SecStr.AppendChar("M")
SecStr.AppendChar("E")
SecStr.AppendChar("T")
Dim Ptr As IntPtr = Marshal.SecureStringToBSTR(SecStr)
Dim Str As String = Marshal.PtrToStringUni(ptr)
Console.WriteLine(Str)




Recent Comments