SQL-Injection, SQL kullanan Web uygulamalarında karşilaşilan en popüler
güvenlik problemi olduğundan; çok uzun girdiler (overlong input) gibi
SQL sorgularıyla ilgili diğer güvenlik tehditleri üzerinde yeterince
durulmamaktadır. Atlanan bu güvenlik tehditleri de, SQL-Injection’lar
gibi ciddi problemler oluşturma potansiyeline sahiptir.
Bu görmezden gelme hali, çok uzun girdilerin genellikle buffer
overflow tarzı problemlere sebep olmasından ileri geliyor olabilir.
Zira, buffer overflow’lar güvenlik uzmanlarının dahi hakkında pek az
bilgiye sahip olduğu ve bu sebeple üzerinde dikkat göstermediği bir
mevzu olarak karşimıza çikmaktadir. Buna karşin, hiçkimsenin
bahsetmediği, SQL sorgularıyla alakalı çok uzun girdilerden kaynağını
alan pek çok farklı ve ciddi problemin varlığı da bir hakikattir.
max_packet_size
MySQL’de; SQL istemcisi ile sunucusu arasında, gönderilen maksimum
veri paketi boyutunu kontrol eden ve varsayılan değeri 1 megabyte
olarak belirlenmiş olan max_packet_size adlı bir konfigürasyon seçeneği
mevcuttur. Sorgular veya sonuç satırları tek bir paket içerisine
uymayacak kadar büyük olursa bir hata oluşur ve çok uzun SQL sorguları
sunucuya ulaştırılmaz, dolayısıyla da çalistirilmaz.
Bu durum, SQL sorgularında kullanılan türden uzun veriler sağlayabilen
saldırganlarca ciddi güvenlik tehlikelerine sebep olacak şekilde
suiistimal edilebilir. Bu meseleye güzel bir örnek, log sorgularında
karşimıza çikmaktadir. Bu sorgular HTTP User-Agent, Session ID ve log
mesajı gibi farklı türden pek çok veriyi geniş bir paket halinde
gönderme imkanı tanıdığından, maksimum paket boyutunun aşilmasına da
sebep olabilir.
Gerçek hayattan bir örnek daha vermek gerekirse; evvela belirtilen parametrelere uyan oturumları bir PHP[Linkleri görebilmek için üye olun veya giriş yapın.]
dizisine aktaran, daha sonra çoklu seviye temizliğini gerçekleştiren
ve son olarak da seçilen tüm oturum id’lerini tek bir silme sorgusunun
içerisine aktaran bir oturum tablosu temizleme işleminden söz
edebiliriz. Anlaşilabileceği gibi, tablodan silinmesi gereken
oturumların çok sayıda tanımlayıcı bilgiye sahip olduğu durumlarda sorgu
çok uzun bir hal alır. Sonuç olarak, uygulama kısa bir zamanda çok
sayıda oturumla şişirildiğinde, kullanılmayan gereksiz oturumlar daha
sonra silinemez hale gelir.
Dolayısıyla Web uygulaması geliştiriciler, sunucuya çok uzun veriler
göndermediklerinden emin olmalıdır. Önceden hazırlanmış ifadeler
(prepared statement) kullanıp kullanmamak burada önemli değildir.
SQL Sütun Kesintisi Açıkları
Kullanıcı girdileri uygulama içerisinde uzunluk yönünden kontrol
edilmediğinde, SQL sütun kesintisi açıkları ortaya çikabilir. SQL sütun
kesintisi açığı, veritabanına veri eklenmesi esnasında uzunluktan
dolayı kesilen çok uzun girdiler sebebiyle oluşan açıkları ifade etmek
üzere kullandığım isimdir. Varsayılan modda MySQL, tanımlı olan
maksimum sütun genişliği değerinden daha büyük olan girdileri keser,
maksimum boyuta kadar gönderilen kısmı işler ve yalnızca bu işleme dair
bir uyarı verir. Bu uyarılar genellikle web uygulamaları tarafından
görülmez ve dikkate alınmaz. MySQL’de sql_mode, STRICT_ALL_TABLES
şeklinde belirlenebilir ve bu uyarıların hata şekline dönüştürülmesi
sağlanabilir; fakat uygulamalar genelde varsayılan modu kullanan
sunucularda çalisir ve uygulamanın kendisi strict modu kullanıyor olsa
bile ilk etapta bu hata üretilemez. Sonuç olarak uygulamalarda uzunluk
kontrolüne başvurulması hayatî ehemmiyettedir.
Veri eklemelerindeki kesintilerin ne gibi problemlere sebep
olabileceğini anlamak için aşağıdaki örnek üzerinde düşünebilirsiniz.
* Uygulama, yeni kullanıcıların kaydolabileceği bir forumdur.
* Administrator yetkisine sahip kullanıcının ismi bilinmektedir (örnegin admin).
* MySQL, varsayılan modda kullanılmaktadır.
* Kullanıcı isimlerinin uzunluğuna dair, uygulamada herhangi bir sınırlama kontrolü mevcut değildir.
* Veritabanında, kullanıcı isimlerini tutma işine tahsis edilmiş sütun
16 karaktere kadar veri kabul edecek şekilde düzenlenmiştir.
Potansiyel bir saldırgan bu şartlar altında "admin " nickini
kaydetmeyi deneyebilir, fakat ‘isAlreadyRegistered’ kontrolü SQL
sorgusunda devreye gireceğinden saldırgan bu hususta muvaffak olamaz.
SELECT * FROM user WHERE username=’admin ’
MySQL, varsayılan modda metin karşilaştırmalarını Binary modunda değil
de güvenlik açısından daha rahat modlarda yapmaktadır. Mesela bu
modlarda metin sonlarındaki boşluk karakterleri yok sayıldığından,
"admin " ve "admin" ifadeleri aynı kabul edilmektedir. Dolayısıyla
uygulama yeni kullanıcı kaydına izin vermeyecektir.
Fakat saldırgan "admin x" nickini kaydetmeyi denediğinde; uygulama,
veritabanında bu kullanıcı ismini arayacak, fakat 16 karakterle
sınırlanmış bir veritabanı alanında 17 karakterli bir veriyi bulmak
mümkün olmayacağından girilen verinin karşilığı veritabanında
çikmayacaktir. Bu durumda uygulama yeni kullanıcı ismini kabul ederek
veri tabanına ekleyecektir. Yalnız veritabanı yalnızca 16 karakter
aldığından, yerleştirilen bu veri 16 karaktere kadar kesilecek ve
boşluk karakterleri de dikkate alınmadığından netice itibarıyla admin
nicki veritabanında iki defa yer bulacaktır.
Sonuç olarak kullanıcı tablosu, sondaki boşlukların yok sayılmasından
dolayı aynı nicke sahip olan iki kullanıcıyı barındırmaktadır ve
yukarıdaki select sorgusu çalistirildiginda her iki nick de döner. Bu
noktada potansiyel bir tehlike oluşur, zira artık iş uygulamanın
nick’leri ne şekilde işlediğine kalmıştır. Mesela aşağıda
göstereceğimiz kod örnegi, öncesinde:
SELECT username FROM users WHERE username = ? AND passhash = ?
sorgusuyla kullanıcı şifresinin doğruluğunu test ettikten sonra
kullanıcı adına bakarak kullanıcıyla ilgili verileri kontrol eden bir
uygulamada açık doğurabilecek tarzdandır:
$userdata = null;
if (isPasswordCorrect($username, $password)) {
$userdata = getUserDataByLogin($username);
...
}
SELECT * FROM users WHERE username = ?
İkinci admin kullanıcısını oluşturan kişi saldırganın bizzat kendisi
olduğundan, bu kontrolü geçmesini sağlayacak şifreyi de bilmektedir.
Gerçek admin kullanıcısı tablonun başinda yer alacağından, daha sonra
kullanıcı verisi isme göre kontrol edilirken ilk etapta döndürülecek
olan kullanıcı da admin yetkilerine sahip olan kullanıcıdır.
Sonuç:
Burada bahsedilen iki problem de, web uygulamaları tarafından dikkate
alınması gereken yeni tehlikelerdir; zira her ikisi de ciddi güvenlik
problemlerine sebep olabilir. Bu açıklar bundan böyle bilinir hale
geldiğinden, takip eden birkaç hafta içerisinde özellikle açık kodlu
yazılımlarda bu noktalarla ilgili tavsiyeler görmek şaşirtıcı
olmayacaktır.
güvenlik problemi olduğundan; çok uzun girdiler (overlong input) gibi
SQL sorgularıyla ilgili diğer güvenlik tehditleri üzerinde yeterince
durulmamaktadır. Atlanan bu güvenlik tehditleri de, SQL-Injection’lar
gibi ciddi problemler oluşturma potansiyeline sahiptir.
Bu görmezden gelme hali, çok uzun girdilerin genellikle buffer
overflow tarzı problemlere sebep olmasından ileri geliyor olabilir.
Zira, buffer overflow’lar güvenlik uzmanlarının dahi hakkında pek az
bilgiye sahip olduğu ve bu sebeple üzerinde dikkat göstermediği bir
mevzu olarak karşimıza çikmaktadir. Buna karşin, hiçkimsenin
bahsetmediği, SQL sorgularıyla alakalı çok uzun girdilerden kaynağını
alan pek çok farklı ve ciddi problemin varlığı da bir hakikattir.
max_packet_size
MySQL’de; SQL istemcisi ile sunucusu arasında, gönderilen maksimum
veri paketi boyutunu kontrol eden ve varsayılan değeri 1 megabyte
olarak belirlenmiş olan max_packet_size adlı bir konfigürasyon seçeneği
mevcuttur. Sorgular veya sonuç satırları tek bir paket içerisine
uymayacak kadar büyük olursa bir hata oluşur ve çok uzun SQL sorguları
sunucuya ulaştırılmaz, dolayısıyla da çalistirilmaz.
Bu durum, SQL sorgularında kullanılan türden uzun veriler sağlayabilen
saldırganlarca ciddi güvenlik tehlikelerine sebep olacak şekilde
suiistimal edilebilir. Bu meseleye güzel bir örnek, log sorgularında
karşimıza çikmaktadir. Bu sorgular HTTP User-Agent, Session ID ve log
mesajı gibi farklı türden pek çok veriyi geniş bir paket halinde
gönderme imkanı tanıdığından, maksimum paket boyutunun aşilmasına da
sebep olabilir.
Gerçek hayattan bir örnek daha vermek gerekirse; evvela belirtilen parametrelere uyan oturumları bir PHP[Linkleri görebilmek için üye olun veya giriş yapın.]
dizisine aktaran, daha sonra çoklu seviye temizliğini gerçekleştiren
ve son olarak da seçilen tüm oturum id’lerini tek bir silme sorgusunun
içerisine aktaran bir oturum tablosu temizleme işleminden söz
edebiliriz. Anlaşilabileceği gibi, tablodan silinmesi gereken
oturumların çok sayıda tanımlayıcı bilgiye sahip olduğu durumlarda sorgu
çok uzun bir hal alır. Sonuç olarak, uygulama kısa bir zamanda çok
sayıda oturumla şişirildiğinde, kullanılmayan gereksiz oturumlar daha
sonra silinemez hale gelir.
Dolayısıyla Web uygulaması geliştiriciler, sunucuya çok uzun veriler
göndermediklerinden emin olmalıdır. Önceden hazırlanmış ifadeler
(prepared statement) kullanıp kullanmamak burada önemli değildir.
SQL Sütun Kesintisi Açıkları
Kullanıcı girdileri uygulama içerisinde uzunluk yönünden kontrol
edilmediğinde, SQL sütun kesintisi açıkları ortaya çikabilir. SQL sütun
kesintisi açığı, veritabanına veri eklenmesi esnasında uzunluktan
dolayı kesilen çok uzun girdiler sebebiyle oluşan açıkları ifade etmek
üzere kullandığım isimdir. Varsayılan modda MySQL, tanımlı olan
maksimum sütun genişliği değerinden daha büyük olan girdileri keser,
maksimum boyuta kadar gönderilen kısmı işler ve yalnızca bu işleme dair
bir uyarı verir. Bu uyarılar genellikle web uygulamaları tarafından
görülmez ve dikkate alınmaz. MySQL’de sql_mode, STRICT_ALL_TABLES
şeklinde belirlenebilir ve bu uyarıların hata şekline dönüştürülmesi
sağlanabilir; fakat uygulamalar genelde varsayılan modu kullanan
sunucularda çalisir ve uygulamanın kendisi strict modu kullanıyor olsa
bile ilk etapta bu hata üretilemez. Sonuç olarak uygulamalarda uzunluk
kontrolüne başvurulması hayatî ehemmiyettedir.
Veri eklemelerindeki kesintilerin ne gibi problemlere sebep
olabileceğini anlamak için aşağıdaki örnek üzerinde düşünebilirsiniz.
* Uygulama, yeni kullanıcıların kaydolabileceği bir forumdur.
* Administrator yetkisine sahip kullanıcının ismi bilinmektedir (örnegin admin).
* MySQL, varsayılan modda kullanılmaktadır.
* Kullanıcı isimlerinin uzunluğuna dair, uygulamada herhangi bir sınırlama kontrolü mevcut değildir.
* Veritabanında, kullanıcı isimlerini tutma işine tahsis edilmiş sütun
16 karaktere kadar veri kabul edecek şekilde düzenlenmiştir.
Potansiyel bir saldırgan bu şartlar altında "admin " nickini
kaydetmeyi deneyebilir, fakat ‘isAlreadyRegistered’ kontrolü SQL
sorgusunda devreye gireceğinden saldırgan bu hususta muvaffak olamaz.
SELECT * FROM user WHERE username=’admin ’
MySQL, varsayılan modda metin karşilaştırmalarını Binary modunda değil
de güvenlik açısından daha rahat modlarda yapmaktadır. Mesela bu
modlarda metin sonlarındaki boşluk karakterleri yok sayıldığından,
"admin " ve "admin" ifadeleri aynı kabul edilmektedir. Dolayısıyla
uygulama yeni kullanıcı kaydına izin vermeyecektir.
Fakat saldırgan "admin x" nickini kaydetmeyi denediğinde; uygulama,
veritabanında bu kullanıcı ismini arayacak, fakat 16 karakterle
sınırlanmış bir veritabanı alanında 17 karakterli bir veriyi bulmak
mümkün olmayacağından girilen verinin karşilığı veritabanında
çikmayacaktir. Bu durumda uygulama yeni kullanıcı ismini kabul ederek
veri tabanına ekleyecektir. Yalnız veritabanı yalnızca 16 karakter
aldığından, yerleştirilen bu veri 16 karaktere kadar kesilecek ve
boşluk karakterleri de dikkate alınmadığından netice itibarıyla admin
nicki veritabanında iki defa yer bulacaktır.
Sonuç olarak kullanıcı tablosu, sondaki boşlukların yok sayılmasından
dolayı aynı nicke sahip olan iki kullanıcıyı barındırmaktadır ve
yukarıdaki select sorgusu çalistirildiginda her iki nick de döner. Bu
noktada potansiyel bir tehlike oluşur, zira artık iş uygulamanın
nick’leri ne şekilde işlediğine kalmıştır. Mesela aşağıda
göstereceğimiz kod örnegi, öncesinde:
SELECT username FROM users WHERE username = ? AND passhash = ?
sorgusuyla kullanıcı şifresinin doğruluğunu test ettikten sonra
kullanıcı adına bakarak kullanıcıyla ilgili verileri kontrol eden bir
uygulamada açık doğurabilecek tarzdandır:
$userdata = null;
if (isPasswordCorrect($username, $password)) {
$userdata = getUserDataByLogin($username);
...
}
SELECT * FROM users WHERE username = ?
İkinci admin kullanıcısını oluşturan kişi saldırganın bizzat kendisi
olduğundan, bu kontrolü geçmesini sağlayacak şifreyi de bilmektedir.
Gerçek admin kullanıcısı tablonun başinda yer alacağından, daha sonra
kullanıcı verisi isme göre kontrol edilirken ilk etapta döndürülecek
olan kullanıcı da admin yetkilerine sahip olan kullanıcıdır.
Sonuç:
Burada bahsedilen iki problem de, web uygulamaları tarafından dikkate
alınması gereken yeni tehlikelerdir; zira her ikisi de ciddi güvenlik
problemlerine sebep olabilir. Bu açıklar bundan böyle bilinir hale
geldiğinden, takip eden birkaç hafta içerisinde özellikle açık kodlu
yazılımlarda bu noktalarla ilgili tavsiyeler görmek şaşirtıcı
olmayacaktır.