Makale Özeti

Querystringlerinizde Id lerinizi herkes görmesin

Makale

  Merhabalar

   Bu yazımın konusu querystring güvenliği üzerine. Querystringde bulunan güvenlik açıklarını basitçe inceleyip daha sonra konu ile ilgili yazmış olduğum querystringi şifreleyen ve çözen bir classın kodlarını inceleyeceğiz.

   Querystring sayfalar arasında veri taşımaya veya bir sayfayı gönderilen bir parametrik değere göre derletmeye veya iş yaptırtmaya yarayan ve sayfa adresinin sonuna ?den sonra eklenen parametredir. Querystringlerde enter karakteri, & karakteri (querystring ayıracı oldugundan dolayı) gibi bazı karakterleri taşımak mümkün değildir ancak yazacağımız şifreleme classı sayesinde bu karakterleride taşıyabilir hale geleceğiz.

   Querystring browserda adres çubuğunda gözüktüğü için kullanıcının bunu değiştirmesi ve ona göre iş yaptırması mümkündür.Örnek verecek olursak;

   Bir mesajlaşma sitemiz olduğunu düşünelim.Kullanıcı kendine gelen mesajları okumak için mesaja tıkladığında http://www.sitemiz.com/mesajOku.aspx?MesajId=234 gibi bir adresi tarayıcının adres çubuğunda görecektir. Ve sonda bulunan MesajId parametresine ait değeri 235 yaparak belkide bir başkasına gelmiş olan mesajı okuyabilecektir.Bunu engellemenin bir yoku mesajOku.aspx sayfası her yüklenirken Parametre olarak gönderilen MesajIdye ait olan değerin kullanıcının mesajlarından birine ait olup olmadığını kontrol ettirmektir.Bu yöntem her sayfa yüklenmesinde veritabanına bağlanacağından dolayı işlemci gücü bakımından maliyetlidir. Bir diğer yöntem ise 234 sayısını kullanıcıya şifreli olarak göstertmek yani sayfayı redirect yaparken veya post ederken MesajId parametresinin değerini bir şifreleme algoritmasından geçirerek şifrelemek ve hedef sayfada bu şifreyi çözmektir bu şifrenin çözülmesi ve şifrelenmesininde elbette işlemciye bir maliyeti olacaktır ancak veri tabanına erişirken yoğunluk yaratmamış olacağız ve gereksiz bağlantılar açıp kapamaktan kaçınacağız. Böylece kullanıcı Querystringde bulunan değeri direkt göremeyecek ve 235 sayısının nasıl kodlandığını bilmediğinden müdahele edemeyecektir.Bunların yanısıra birçok site arka planda çalışan Id leri kullanıcılara göstermek istemez.Bunun içinse querystring yine şifrelenmelidir.

   Şifreleme algoritmasını gerçekleştiriken querystringde bulunması hataya sebep karakterler üretmekten kaçınmalıyız.Yani oluşturacağımız şifreler hep bir gurup değerden oluşmalı ve bunun dışına çıkmamalıdır. Bunun için ise güzel bir yöntem mod kullanarak bir şifreleme geliştirmektir. Vede querystring şifrelemelerini çok uzun karakterler üretecek şekilde yapmamakta fayda vardır.

Public Class QueryStringCryptography
   Function encrypt(ByVal textToEncrypt As String) As String
      Dim rnd As New Random
      Dim crypterNumber As Integer
      Dim level1Encrypted As Integer
      Dim encryptedText As String
      Dim encryptedDigit As String
Classımızı tanımladıktan sonra şifreleme işlemini gerçekleşterecek olan fonksiyonumuzu metinsel parametre olarak şifrelenmek istediğimiz metni alacak ve geriye şifreli metni döndürecek şekilde tanımlıyoruz.Ve daha sonra şifreleyecek gizli numarayı,birinci seviyede şifrelediğimiz metni,şifreli metni ve şifreli karakterleri tutacağımız değişkenlerimizi tanımlıyoruz.

      For i As Integer = 0 To textToEncrypt.Length - 1
         crypterNumber = rnd.Next(65, 90)
         level1Encrypted = Asc(textToEncrypt.Substring(i, 1)) * crypterNumber
         encryptedDigit = ConvertBase(level1Encrypted, 10, 33)
         Select Case encryptedDigit.Length
            Case 1
               encryptedDigit = "00" & encryptedDigit
            Case 2
               encryptedDigit = "0" & encryptedDigit
         End Select
         encryptedText &= Chr(crypterNumber) & encryptedDigit
      Next
   For döngüsündende anlaşılabileceği gibi şifrelenecek metinde bulunan her bir karakter için şifreleme işlemi tek tek gerçekleştirip for döngüsünün son satırında birleştirilecektir.Şimdi şifrelemenin mantığını inceleyelim;
   Elde ettiğimiz tek haneli karakterin ascii kodunu her karakter için farklı olarak randomize üretiiğimiz bir sayı ile çarpıyoruz.(Randomize ürettiğimiz bu sayının sınırlarını 65 ile 90 arası tanımlıyoruz çünkü büyük harflerin ascii kodları bu aralıktadır.).

   Çarpma işleminden sonra elimizde oluşan sayıyı 10luk sayma düzeninden 33lük sayma düzenine çeviriyoruz.*(Bu çevirme işlemi ile ilgili bilgi yaznın en sonunda verilecektir.)

   Şifreleyeceğimiz sayı en fazla 255(en büyük ascii kodu) oldugundan vede randomize üretilecek sayımız en falza 90 olduğundan, çarpımlarının en büyük değeri 22950 olacaktır. Buda 33lük sayma düzeninde 3 basamakla tanımlanabilecek bir sayıya denk geldiğinden. 3 basamaktan az olarak şifrelenen karakterleri başlarına etkisiz eleman olan 0ı koymak suretiyle 3 basamaklı hale getiriyoruz.
   Metni şifreleyen ve randomize üretilen bir sayı üretip buna göre şifrelemiştik, buda demek oluyorki şifreli metni çözmek için yine bu sayıya ihtiyaç duyacağız.O zaman bu sayıyıda bir şekilde şifreleyerek bu şifreli metnin içine dahil etmeliyiz. Bunun için izleyeceğimiz yöntem sayıyı rastgele üretirken verdiğimiz aralıktan orataya çıkacak vede şifreleyen sayıyı ascii koduna karşılık gelen karakter ile tanımlayacağız ve bunu her basamak için daha önceden ürettiğimiz 3er haneli gurupların başına ekleyeceğiz.

      Return encryptedText
   End Function
   Fonksiyonumuzun geriye döndüreceği değeri tanımlıyoruz vede fonksiyonumuzu bitiriyoruz.

    Şimdi ise querystringin gönderildiği sayfada şifresini çözen fonksiyonu inceleyelim.

   Function decrypt(ByVal textToDecrypt As String) As String
      Dim encryptedDigit As String
      Dim level1Encrypted As Integer
      Dim crypterNumber As Integer
      Dim decryptedtext As String
   Fonksiyonumuzu metinsel parametre olarak şifreli metni alıp geriye şifresi çözülmüş metni döndürecek şekilde tanımlıyoruz ve şifreli karakteri,şifreleyen sayıyı ve şifresi çözülmüş metni tutacağımız değişkenleri tanımlıyoruz.

      For i As Integer = 0 To textToDecrypt.Length / 4 - 1
         encryptedDigit = textToDecrypt.Substring(i * 4, 4)
         crypterNumber = Asc(encryptedDigit.Substring(0, 1))
         encryptedDigit = encryptedDigit.Substring(1, 3)
         If encryptedDigit.Substring(0, 2) = "00" Then
            encryptedDigit = encryptedDigit.Substring(2, 1)
         ElseIf encryptedDigit.Substring(0, 1) = "0" Then
            encryptedDigit = encryptedDigit.Substring(1, 2)
         End If
         level1Encrypted = ConvertBase(encryptedDigit, 33, 10)
         decryptedtext &= Chr(level1Encrypted / crypterNumber)
      Next
   Şifremiz her karakter başına 4 karakterden(ilk karakter şifreleyen gizli sayının karakteri) oluştuğu için gelen şifreli metini dört hane dört hane inceleyip şifreleri parça parça çözerek sonda birleştireceğiz.Buna göre for döngüsünü yazıyoruz.
   İlk karakteri alıp şifresini çözerek şifreleyen gizli sayıyı elde ediyoruz. Daha sonra geri kalan üç hanelik grubun başında 0lar varsa bunları atıyoruz(şifrelerken üç haneden az oluşan şifre parçacıklarını üç haneye tamamlamak için eklediğimiz 0 lar).

   Daha sonra elde ettiğimiz sayıyı 33lük sayma düzeninden 10luk sayma düzenine çeviriyoruz. *

   Son adımda ise şifreleyen sayıya bölüp şifrelediğimiz karakterin ascii kodunu buluyoruz. Buradanda karaktere geri dönüşüm yapıyoruz. Bu işlemi 4erli her gurup için yapıp birleştirdiğimizde şifreli metnin şifresini çözmüş oluyoruz.

      Return decryptedtext
   End Function
   Çözdüğümüz şifrenin değerini geriye döndürerek fonksiyonu bitiriyoruz.

   Aşağıda bulunan fonksiyonun görevi sayıların tabanlarını değiştirmektir.Bu fonksiyon ilgili ayrıntılı bilgiye ve çalışma mantığına daha önceden yazmış olduğum bir yazıdan ulaşabilirsiniz.Bu makaleye ulaşmak için tıklayınız.
   Ancak belirttiğim makaleden ufak bir farkı vardır oda burada 33 elemandan oluşan bir dizi kullanılarak 33lük sayma tabanı işlemi yapabilme yeteneğidir.

   Public Function ConvertBase(ByVal NumberToConvert As String, ByVal NumbersBase As Short, ByVal TargetBase As Short) As String
      Dim basesNumbers() As String = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "R", "S", "T", "U", "V", "Y", "Z"}
      Dim NumberConvertedTo10Base As Integer = 0
      If NumbersBase = 10 Then
         NumberConvertedTo10Base = NumberToConvert
      Else
         For i As Integer = 0 To NumberToConvert.Length - 1
            NumberConvertedTo10Base += basesNumbers.IndexOf(basesNumbers, NumberToConvert.Substring(NumberToConvert.Length - 1 - i, 1)) * Math.Pow(NumbersBase, i)
         Next
      End If
      Dim NumberConvertedToTargetBase As String
      If TargetBase = 10 Then
         NumberConvertedToTargetBase = NumberConvertedTo10Base.ToString
      Else
         Do Until NumberConvertedTo10Base = 0
            NumberConvertedToTargetBase = basesNumbers((NumberConvertedTo10Base Mod TargetBase).ToString) & NumberConvertedToTargetBase
            NumberConvertedTo10Base = Math.Floor(NumberConvertedTo10Base / TargetBase)
         Loop
      End If
      Return NumberConvertedToTargetBase
   End Function
End Class
Tabiki bu fonksiyon çağırılırken try catch blokları içine yazıp bir hata oluşması durumunda kullanıcıyı bir hata sayfasına yönlendirmekte fayda vardır. Ayrıca güvenliği hiçbir zaman elden bırakmamak için yazının başında bahsettiğim olay olan gelen her parametreyi veri tabanında o kullanıcının erişebileceği bir veriye ait parametremi diye kontrol ettirmekte ve bu classı sadece id ler çok aleni bir şekilde görülmesini engellemek için kullanmakta fayda vardır.

Bu makalede bulunan classdaki şifreleyen sayıyı şifreleme tekniğini değiştirip daha karmaşık bir hale getirerek daha sağlam bir şifreleme elde edebilirsiniz.Veya şifreleyeceğiniz metni iki kademeli şifrelemeden geçirerek çok daha kararlı ve güvenli bir yapı elde edebilirsiniz.

Bu şifreleme yönteminden önce bir ön şifre oluşturmak isterseniz kullanabileceğiniz bir şifreleme yöntemine ait kodları ve açıklamayı buradan okuyabilirsiniz.

Kodları indirmek için tıklayın.

Tamer ÖZ

oztamer@hotmail.com
tamer.oz@yazgelistir.com
oztamer@hotmail.com