Merhaba dostlar! Yine bir teknoloji sohbetiyle karşınızdayım. Biliyorsunuz, yazılım dünyasında her zaman yeni şeyler öğreniyoruz, bazen de eski konulara dönüp eksiklerimizi kapatıyoruz. Bugün de aklıma takılan, üzerine düşünmem gereken bir konu var: Parametreli sorgular ve SQL Injection denen o meşhur güvenlik açığı. Ne güzel değil mi?
Şimdi şöyle düşünün, web siteleri veya uygulamalarımız veritabanlarıyla konuşuyor, onlardan bilgi alıyor, onlara bilgi gönderiyor. Bu iletişim sırasında kullandığımız en temel yöntemlerden biri SQL sorguları. Ama işte tam bu noktada, karşıdan gelen veriye yeterince dikkat etmezsek, başımıza neler gelebileceğini bir hayal edin. Bir düşünün, kendi evinizin kapısını tanımadığınız birine anahtarla birlikte mi verirdiniz? İşte SQL Injection da biraz böyle bir şey. Kötü niyetli birisi, bizim yazdığımız SQL sorgusunun içine kendi zararlı komutlarını sokuşturuyor ve veritabanımızla istediği gibi oynuyor. Bu da bizim için hem veri kaybı hem de güvenlik zafiyeti demek. Tabi hiç hoş değil.
Geçenlerde bir arkadaşımın projesinde şöyle bir durumla karşılaştık: Kullanıcıdan aldığı bir girdiyi doğrudan bir SQL sorgusuna ekliyordu. Yani düşünün, kullanıcı adı ve şifre yerine ‘ OR ‘1’=’1′ –‘ gibi bir şey yazınca, sorgu direkt olarak tüm kullanıcıların giriş yapmasına izin veriyordu. O an arkadaşımın yüzündeki ifadeyi görmeliydiniz. Kendi programım sınıfta kaldı diyebilirim o an 🙂
İşte bu tür problemlerle karşılaşmamak için parametreli sorgular gibi güvenli yöntemlere başvurmamız şart. Parametreli sorgular, bizim gönderdiğimiz veriyi SQL kodundan ayrı tutarak, sorgunun yapısını bozmasını engelliyor. Yani siz veritabanına ‘kullanıcı adı’ olarak bir şey gönderiyorsunuz, ama sistem bunu ‘kullanıcı adı’ değeri olarak alıyor, SQL kodu olarak değil. Bu kadar basit bir mantıkla bile ne kadar büyük bir güvenlik açığını kapatmış oluyoruz, değil mi?
Peki, bu parametreli sorguları nasıl kullanıyoruz? Aslında çoğu modern programlama dili ve veritabanı erişim kütüphanesi bunu destekliyor. Mesela C#’ta ADO.NET kullanıyorsak, `SqlCommand` objesini oluştururken parametreleri ayrı ayrı ekleyebiliyoruz. Ya da Dapper gibi daha kullanışlı ORM’ler de zaten bunu arka planda bizim için hallediyor. Bu arada, benim şu sıralar C# ve Dapper ile REST API geliştirdiğimi biliyorsunuz, orada da bu işleri hep parametreli sorgularla hallediyorum, hem hızlı hem güvenli.
Şimdi gelelim işin pratiğine. Diyelim ki bir kullanıcıdan ID’sini alıp, o ID’ye ait bilgileri getireceğiz. Eski ve güvensiz yöntemle bu şöyle olabilirdi:
// YANLIŞ KULLANIM (SQL Injection'a AÇIK!) string userId = Request.Query["id"]; // Kullanıcıdan gelen ID string query = "SELECT * FROM Users WHERE Id = " + userId; // Bu sorguya ' OR '1'='1' -- gibi bir şey gelirse, tüm kullanıcılar döner :)
Gördüğünüz gibi, `userId` değişkenini doğrudan sorgunun içine ekledik. Bu tam bir felaket senaryosu. Şimdi bunu güvenli hale getirelim:
Bu arada, bu tür güvenlik açıklarını daha detaylı incelemek isterseniz, Google’da SQL Injection örnekleri diye aratırsanız bolca kaynak bulabilirsiniz. Hatta YouTube’da da bununla ilgili güzel demolar var, tutorial diye aratıp izleyebilirsiniz.
İşte düzeltilmiş, güvenli hali:
// DOĞRU KULLANIM (Parametreli Sorgu ile Güvenli) string userId = Request.Query["id"]; using (var command = new SqlCommand("SELECT * FROM Users WHERE Id = @UserId", connection)) { command.Parameters.AddWithValue("@UserId", userId); // Sorguyu çalıştır ve sonuçları al... // Artık userId ne olursa olsun, veritabanı bunu sadece bir değer olarak görür, kod olarak değil. // Ne güzel değil mi? }
Bu kod bloğunda `command.Parameters.AddWithValue(“@UserId”, userId);` kısmı olayı çözüyor. `@UserId` bizim SQL sorgumuzdaki yer tutucumuz, `userId` değişkeni ise bu yer tutucunun değeri. Bu ayrım sayesinde, gelen `userId` değeri ne kadar “kurnazca” olursa olsun, veritabanı onu sadece bir metin parçası olarak işleyecek ve asla kendi başına bir SQL komutu olarak algılamayacak. Bu arada, bazı kütüphanelerde bu parametre tipi daha detaylı belirlenebiliyor ama `AddWithValue` çoğu senaryo için işimizi görüyor sanırım.
Neticede, yazılım geliştirirken güvenlik en öncelikli konulardan biri olmalı. Hele ki veritabanına doğrudan veri yazıp okuyorsak, parametreli sorguları kullanmak bir alışkanlık haline gelmeli. Bu, hem bizim işimizi kolaylaştırır hem de uygulamalarımızın güvenliğini sağlam temellere oturtur. Bana göre, her geliştiricinin bu konuda bilinçli olması gerekiyor. Yani bir nevi, her gün diş fırçalamak gibi düşünün bunu. 🙂
Sonuç olarak, parametreli sorgular SQL Injection gibi saldırılara karşı en etkili savunma mekanizmalarından biri. Kullandığımız dilde veya kütüphanede bu özelliği destekleyen bir yapı varsa, onu mutlaka kullanmalıyız. Unutmayalım ki, bizim yazdığımız tek bir satır kod, ileride büyük sorunlara yol açabilir. Onun için dikkatli olalım, güvenli kod yazalım.
Bu arada, bu konuyu daha derinlemesine anlamak için Wikipedia’daki SQL injection sayfasını da inceleyebilirsiniz. Orada da güzel açıklamalar mevcut.
Ne desem ki… işte böyle bir şey. Parametreli sorgular candır, gerisi yalandır diyerek bu sohbeti noktalıyorum. Umarım faydalı olmuştur. Kendinize iyi bakın!