Güvenlik & SSL

    SQL Injection Nedir ve Nasıl Önlenir?

    SQL injection saldırısının mantığını, örneklerini ve parametreli sorgu ile korunmayı anlatan güvenlik rehberi.

    12 dk okuma Güncellendi: 10 Temmuz 2026

    Bir web uygulamasının aldığı en kritik varlık genellikle veritabanıdır. Kullanıcı adları, parola özetleri, sipariş kayıtları, fatura bilgileri, iletişim formundan gelen mesajlar; hepsi orada durur. SQL injection, saldırganın bir formu ya da bir URL parametresini kullanarak bu veritabanına doğrudan komut göndermesine izin veren bir açıktır. Adı karmaşık gelse de mantığı son derece basittir: uygulama, kullanıcıdan gelen metni "veri" olarak değil, çalıştırılacak "komut" olarak yorumlar. Aradaki bu tek karışıklık, bir tablonun tamamının dışarı sızmasıyla sonuçlanabilir.

    Bu rehberde SQL injection'ın nasıl ortaya çıktığını gerçek kod örnekleriyle göstereceğiz. Klasik, kör (blind) ve union tabanlı saldırı türlerini kısaca ayıracağız; ardından işin en önemli tarafına, korunmaya geçeceğiz. Parametreli sorgular, girdi doğrulama, en az yetkili veritabanı kullanıcısı ve web uygulama güvenlik duvarı (WAF) katmanını bir sistem yöneticisinin gözünden, sahada gerçekten işe yarayan detaylarla anlatacağız. Amaç sadece "tehlikeli" demek değil; kodunuzu ve sunucunuzu somut olarak nasıl sağlamlaştıracağınızı göstermek.

    SQL Injection Tam Olarak Nedir?#

    SQL (Structured Query Language), veritabanıyla konuşmanın dilidir. Bir kullanıcı giriş yaptığında uygulama arka planda genelde şuna benzer bir sorgu kurar: "şu e-postaya ve şu parolaya sahip kullanıcıyı getir". Sorun, uygulamanın bu cümleyi kullanıcıdan gelen metni satır içine yapıştırarak kurmasıdır. Kullanıcı e-posta alanına normal bir e-posta yerine SQL'in kendi işaretlerini yazarsa, cümlenin anlamı tamamen değişir.

    Aşağıdaki PHP örneği bu açığı tek satırda özetler. Burada $_POST ile gelen değer hiçbir işlemden geçmeden sorgunun içine gömülüyor:

    // ZAFİYETLİ KOD - asla böyle yazmayın
    $email = $_POST['email'];
    $pass  = $_POST['password'];
    
    $sql = "SELECT id, name FROM users
            WHERE email = '$email' AND password = '$pass'";
    $result = $conn->query($sql);
    

    Normal bir kullanıcı [email protected] yazdığında sorgu beklendiği gibi çalışır. Ama saldırgan e-posta alanına şunu yazarsa işler değişir:

    ' OR '1'='1' -- 
    

    Bu girdi sorgunun içine yapıştığında ortaya çıkan cümle şu hâle gelir:

    SELECT id, name FROM users
    WHERE email = '' OR '1'='1' -- ' AND password = '...'
    

    Burada '1'='1' her zaman doğrudur, -- işareti ise satırın geri kalanını (parola kontrolünü) yorum satırına çevirip iptal eder. Sonuç: uygulama parolayı hiç kontrol etmeden ilk kullanıcıyı, çoğunlukla yönetici hesabını döndürür. Saldırgan tek bir karakterle giriş ekranını aşmış olur. Aynı mantık arama kutularında, filtrelerde, sipariş numarası parametrelerinde ve API uç noktalarında da geçerlidir. Sorunun kaynağı formun kendisi değil, gelen metnin komutla karışmasıdır.

    Bir Saldırının Adım Adım İşleyişi#

    Gerçek bir saldırı nadiren tek hamlede biter. Saldırgan önce zafiyeti tespit eder, sonra veritabanının yapısını haritalar, en sonunda veriyi çeker. İlk adım genellikle bir alana tek tırnak (') göndermektir. Uygulama SQL hatası döndürür ya da beklenmedik bir davranış sergilerse, girdinin sorguya karıştığı anlaşılır.

    Örneğin bir ürün sayfası urun.php?id=15 biçiminde çalışıyorsa, saldırgan sırasıyla şunları dener:

    urun.php?id=15'            -> hata verirse zafiyet sinyali
    urun.php?id=15 AND 1=1     -> normal sonuç döner
    urun.php?id=15 AND 1=2     -> boş sonuç döner
    

    Son iki satırın farklı davranması, uygulamanın gönderilen mantıksal ifadeyi gerçekten veritabanında çalıştırdığını kanıtlar. Bu noktadan sonra saldırgan tablo ve sütun adlarını, veritabanı sürümünü, hatta dosya sistemine erişim olup olmadığını öğrenmeye çalışır. Otomatik araçlar bu adımları saniyeler içinde tekrarlayabildiği için, açık bir uç nokta internette çok kısa sürede taranıp bulunur. Yani "benim sitemi kim fark eder" düşüncesi geçersizdir; taramalar hedef gözetmeksizin, botlarla toplu yapılır.

    SQL Injection Türleri#

    SQL injection tek bir teknik değil, bir aile. Saldırganın veriyi nasıl geri aldığına göre üç ana gruba ayırmak pratik bir yaklaşımdır. Aşağıdaki tablo bu türleri hızlıca karşılaştırıyor:

    TürNasıl çalışırGeri bildirimTespit güçlüğü
    Klasik (in-band)Veri doğrudan sayfada görünürAnında, açıkDüşük
    Union tabanlıUNION ile başka tabloların verisi eklenirAnında, açıkDüşük-orta
    Kör (blind)Doğru/yanlış ya da süre farkından çıkarım yapılırDolaylıYüksek

    Bu türleri ayrı ayrı görmek, korunmanın neden tek noktaya odaklanmaması gerektiğini de anlatır.

    Klasik (In-Band) Injection#

    En basit ve en gürültülü türdür. Saldırgan zararlı ifadeyi gönderir, sonuç aynı sayfada karşısına çıkar. Giriş ekranını aşan ' OR '1'='1 örneği bu kategoridedir. Hata mesajları ekrana basılıyorsa saldırganın işi daha da kolaylaşır; çünkü hatalar veritabanı türünü ve sorgu yapısını ele verir.

    Union Tabanlı Injection#

    Bu teknik SQL'in UNION operatörünü kötüye kullanır. UNION, iki ayrı sorgunun sonucunu tek listede birleştirir. Saldırgan, sayfanın normalde gösterdiği sorguya kendi sorgusunu ekler ve örneğin kullanıcı tablosunu ürün listesinin içine sızdırır:

    15 UNION SELECT username, password FROM users -- 
    

    Uygulama bu birleşik sonucu ürün adı sanıp ekrana yazdığında, kullanıcı adları ve parola özetleri ürün listesinin içinde belirir. İki sorgunun sütun sayısı ve türü uyumlu olması gerektiği için saldırgan önce sütun sayısını dener, sonra veriyi çeker.

    Kör (Blind) Injection#

    En sinsi türdür çünkü ekranda hiçbir veri görünmez. Uygulama zararlı girdiye "var/yok" veya "gecikti/gecikmedi" gibi dolaylı tepkiler verir, saldırgan da bu tepkilerden bit bit veri okur. İki alt biçimi vardır. Boolean tabanlıda sayfa doğru koşulda normal, yanlış koşulda boş döner. Zaman tabanlıda ise saldırgan veritabanını kasıtlı bekletir:

    15 AND IF(SUBSTRING(version(),1,1)='8', SLEEP(5), 0) -- 
    

    Sayfa 5 saniye gecikiyorsa, veritabanı sürümünün 8 ile başladığı anlaşılır. Bu yöntem yavaştır ama otomatik araçlarla tüm parola özetini karakter karakter çıkarmak mümkündür. Ekranda hata görünmediği için sunucu loglarına bakmayan ekiplerin bu saldırıyı fark etmesi çok zordur.

    Korunmanın Temeli: Parametreli Sorgular#

    SQL injection'a karşı en sağlam ve tartışmasız savunma parametreli sorgulardır (prepared statements). Mantık şudur: sorgunun iskeletini önceden tanımlarsınız, kullanıcı verisini ise ayrı bir kanaldan "parametre" olarak gönderirsiniz. Böylece veritabanı, gelen metni ne olursa olsun daima "veri" kabul eder, asla komut olarak yorumlamaz. Kullanıcı ' OR '1'='1 yazsa bile bu metin olduğu gibi aranır ve hiçbir kayıt bulunmaz.

    Aynı giriş sorgusunun güvenli PHP (PDO) hâli şudur:

    // GÜVENLİ - parametreli sorgu
    $sql = "SELECT id, name FROM users
            WHERE email = ? AND password = ?";
    $stmt = $pdo->prepare($sql);
    $stmt->execute([$email, $passwordHash]);
    $user = $stmt->fetch();
    

    Buradaki ? işaretleri yer tutucudur; execute ile gönderilen değerler sorgu iskeletine karışmaz. Node.js tarafında da mantık aynıdır:

    // GÜVENLİ - mysql2 ile parametreli sorgu
    const [rows] = await conn.execute(
      'SELECT id, name FROM users WHERE email = ? AND password = ?',
      [email, passwordHash]
    );
    

    Python (psycopg / sqlite3) için de tek kural değişmez; değerleri asla string birleştirmeyle sorguya eklemeyin:

    # GÜVENLİ - parametreleri ayrı geçirin
    cur.execute(
        "SELECT id, name FROM users WHERE email = %s AND password = %s",
        (email, password_hash),
    )
    

    Modern ORM'ler (Laravel Eloquent, Doctrine, Sequelize, Django ORM, Prisma) varsayılan olarak parametreli sorgu kullanır. Yani framework kullanıyorsanız zaten büyük ölçüde korunmuş olursunuz. Tehlike, "hız için" veya "karmaşık sorgu yazmak için" ham SQL'e döndüğünüz ve değerleri elle birleştirdiğiniz yerlerde başlar. Bir tek yerde string birleştirme kullanmak, uygulamanın geri kalanı ne kadar temiz olursa olsun kapıyı açar. Kod incelemelerinde en çok bakılması gereken nokta budur.

    Diğer Katmanlar: Girdi Doğrulama, En Az Yetki ve WAF#

    Parametreli sorgu zorunlu temeldir; ama güvenlik tek katmana yaslanmaz. İyi bir sistem yöneticisi, bir savunma delinse bile arkada başka bir katman dursun ister. SQL injection için üç ek katman özellikle önemlidir.

    Girdi doğrulama, gelen verinin beklenen biçimde olup olmadığını kontrol eder. Bir kimlik parametresi yalnızca sayı olmalıysa, sayı olmayan her girdiyi baştan reddedin. Bu, saldırıyı tamamen durdurmasa da saldırı yüzeyini daraltır ve pek çok otomatik denemeyi erkenden eler:

    // id sadece pozitif tam sayı olabilir
    $id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);
    if ($id === false || $id < 1) {
        http_response_code(400);
        exit('Geçersiz istek');
    }
    

    En az yetkili veritabanı kullanıcısı ilkesi, bir sızma yaşandığında zararı sınırlar. Web uygulamanız veritabanına root ile bağlanıyorsa, saldırgan tabloları silebilir, yeni kullanıcı yaratabilir, hatta bazı yapılandırmalarda dosya okuyabilir. Oysa uygulama yalnızca kendi veritabanında SELECT, INSERT, UPDATE yetkisine sahip bir kullanıcıyla bağlansa, aynı açık çok daha az zarar verir. Ayrı bir kullanıcı oluşturmak birkaç satırlık iştir:

    CREATE USER 'app_user'@'localhost' IDENTIFIED BY 'guclu-bir-parola';
    GRANT SELECT, INSERT, UPDATE, DELETE
      ON uygulama_db.* TO 'app_user'@'localhost';
    FLUSH PRIVILEGES;
    

    Dikkat edilecek nokta, DROP, ALTER, FILE gibi yetkileri bu kullanıcıya vermemektir. Uygulamanın günlük işleyişi için bunlara ihtiyaç yoktur; şema değişikliklerini ayrı bir yönetim kullanıcısıyla yaparsınız.

    Web uygulama güvenlik duvarı (WAF) ise trafiği uygulamaya ulaşmadan önce süzen dış katmandır. UNION SELECT, SLEEP(, information_schema gibi tipik injection kalıplarını içeren istekleri yakalayıp engeller. WAF, koddaki bir açığın yerine geçmez; bilinen saldırı imzalarını filtreleyerek size tepki verme zamanı ve ek bir emniyet ağı kazandırır. Özellikle kodunu doğrudan değiştiremediğiniz üçüncü parti eklentiler ve eski uygulamalar için değeri büyüktür. WAF'ın nasıl çalıştığına ve neyi çözüp neyi çözmediğine daha derin bakmak isterseniz web uygulama güvenlik duvarı (WAF) rehberimizi okuyabilirsiniz. Clou.TR tarafında bu katmanı hazır almak isterseniz WAF hizmetimize ve tam kapsamlı DDoS koruma çözümümüze göz atabilirsiniz.

    Nginx ve Loglarla Erken Uyarı#

    Kod düzeyinde savunmayı kurduktan sonra, saldırı denemelerini görebilmek de önemlidir. Sunucu tarafında basit bir filtre, en kaba injection denemelerini daha kapıda düşürebilir. Aşağıdaki Nginx örneği, sorgu string'inde tipik injection kalıplarını gördüğünde isteği reddeder:

    # Kaba injection kalıplarını erken engelle
    location / {
        if ($args ~* "(union.*select|information_schema|sleep\(|benchmark\()") {
            return 403;
        }
        try_files $uri $uri/ /index.php?$query_string;
    }
    

    Bu kural tek başına yeterli bir güvenlik değildir; kod düzeyindeki parametreli sorguların yerini asla tutmaz. Ancak gürültülü otomatik taramaları azaltır ve log dosyalarını sadeleştirir. Asıl kıymetli iş, logları düzenli izlemektir. Erişim loglarında union select, sleep( veya arka arkaya gelen 400/403 yanıtları bir tarama sinyalidir:

    # Şüpheli istekleri erişim logunda ara
    grep -iE "union.*select|information_schema|sleep\(" /var/log/nginx/access.log
    
    # Aynı IP'den yoğun hatalı istekleri say
    awk '($9 ~ /40[0-9]/){print $1}' /var/log/nginx/access.log \
      | sort | uniq -c | sort -rn | head
    

    Bu izlemeyi elle yapmak yerine bir sunucu yönetimi hizmetiyle otomatikleştirmek çoğu ekip için daha sürdürülebilirdir. Yönetimini bize bırakmak isterseniz sunucu yönetimi hizmetimiz bu tür log izleme, güncelleme ve sıkılaştırma işlerini üstlenir. Uygulamanızı WordPress üzerinde yürütüyorsanız, eklenti kaynaklı açıklar en yaygın giriş kapısıdır; bu konuya özel önlemleri WordPress güvenliği rehberimizde topladık.

    Yaygın Yanlış İnanışlar#

    SQL injection etrafında hâlâ dolaşan birkaç hatalı inanış, ekipleri sahte bir güven duygusuna sürükler. En sık rastlananı, "tek tırnakları temizlersem sorun kalmaz" düşüncesidir. Elle karakter kaçışlama (escaping) kırılgandır; farklı karakter kodlamaları, çok baytlı karakterler ve unuttuğunuz tek bir alan bu savunmayı deler. Doğru çözüm karakter temizlemek değil, veriyi baştan komuttan ayıran parametreli sorgudur.

    İkinci yanılgı, "sitem küçük, kimse uğraşmaz" varsayımıdır. Saldırıların ezici çoğunluğu insan eliyle değil, internetin tamamını gezen botlarla yapılır; bu botlar için sitenizin büyüklüğü ya da ziyaretçi sayısı fark etmez. Üçüncü yanılgı, "HTTPS/SSL kullanıyorum, güvendeyim" düşüncesidir. SSL yalnızca tarayıcı ile sunucu arasındaki trafiği şifreler; injection ise şifreli tünelin içinde, geçerli bir istek gibi gelir. SSL sertifikası olmazsa olmazdır ama SQL injection'ı önlemez. Bu iki katmanı birbirine karıştırmamak gerekir; ihtiyacınız olan SSL sertifikası ile uygulama güvenliği birbirini tamamlayan ama ayrı konulardır. Son olarak "framework kullanıyorum, otomatik korunuyorum" rahatlığı da kısmen doğru olsa bile ham sorgu yazdığınız her istisna noktasında geçersizdir; asıl açıklar tam o istisnalarda çıkar.

    Sıkça Sorulan Sorular#

    SQL injection sadece giriş formlarını mı etkiler?#

    Hayır, kullanıcıdan gelen herhangi bir değerin sorguya karıştığı her nokta risklidir. Giriş formları en bilinen örnektir ama arama kutuları, ürün filtreleri, sayfalama parametreleri, sıralama seçenekleri, çerez değerleri, HTTP başlıkları ve API gövdeleri de aynı açığa sahip olabilir. Kural basittir: kullanıcının etkileyebildiği hiçbir veri, doğrudan sorgu metnine yapıştırılmamalıdır. Bu yüzden savunmayı forma değil, veri erişim katmanının tamamına uygulamak gerekir.

    Parametreli sorgu kullanınca ORM'e gerek kalır mı?#

    ORM zorunlu değildir; parametreli sorgu tek başına yeterli korumayı sağlar. ORM'ler işi kolaylaştırır çünkü çoğu sorguyu sizin adınıza parametreli üretir, ama düz PDO, mysqli veya psycopg gibi kütüphanelerle elle yazdığınız parametreli sorgular da aynı derecede güvenlidir. Önemli olan aracın adı değil, kullanıcı verisini asla sorgu iskeletiyle birleştirmemenizdir. ORM kullansanız bile ham SQL yazdığınız yerlerde aynı kurala uymanız gerekir.

    WAF kurarsam kodumu düzeltmesem olur mu?#

    Olmaz, WAF ek bir katmandır ama koddaki açığın yerini tutmaz. WAF bilinen saldırı kalıplarını filtreler; ancak yeni ya da özenle gizlenmiş bir yük filtreyi aşabilir, o zaman geriye yalnızca koddaki savunma kalır. Doğru yaklaşım önce parametreli sorgularla kodu sağlamlaştırmak, sonra WAF'ı ikinci bir emniyet ağı olarak eklemektir. WAF'ı tek başına savunma sanmak, kilitli olmayan bir kapıya sadece kamera koymaya benzer; olayı görürsünüz ama engellemezsiniz.

    Sitemin SQL injection açığı olduğunu nasıl anlarım?#

    En pratik ilk adım, parametrelere tek tırnak göndererek uygulamanın SQL hatası döndürüp döndürmediğine bakmaktır; ekrana veritabanı hatası basılıyorsa güçlü bir sinyaldir. Daha sistemli bir kontrol için otomatik güvenlik tarayıcıları ve manuel test kullanılır. Erişim loglarında union select veya sleep( gibi kalıpların görülmesi de birilerinin denediğini gösterir. Emin değilseniz bir güvenlik taraması yaptırmak veya sunucu yönetimi ekibinden uygulamanızı denetlemesini istemek en sağlıklısıdır.

    Var olan eski bir uygulamada tüm sorguları düzeltmek zorunda mıyım?#

    İdeal olan evet, ama iş genellikle önceliklendirmeyle yürür. Önce kullanıcı girdisini alan ve ham SQL kullanan noktaları çıkarır, en yüksek riskli olanlardan başlarsınız; giriş, arama ve yönetim panelleri genellikle ilk sıradadır. Bu geçiş süresince WAF ve en az yetkili veritabanı kullanıcısı, henüz düzeltilmemiş yerlerin zararını sınırlar. Yani WAF ve yetki kısıtlaması, kodu temizlerken size zaman kazandıran geçici köprülerdir; ama nihai hedef her sorgunun parametreli hâle gelmesidir.

    Yedek almak SQL injection'a karşı korur mu?#

    Yedek, saldırıyı önlemez ama sonrasında ayakta kalmanızı sağlar. Bir saldırgan tabloları sildiğinde ya da veriyi bozduğunda, güncel ve test edilmiş bir yedek felaketi birkaç saatlik bir kesintiye indirir. Yedek olmadan aynı olay kalıcı veri kaybına dönüşür. Bu yüzden yedeklemeyi güvenliğin alternatifi değil, tamamlayıcısı olarak görmek gerekir; önleme katmanları saldırıyı durdurur, yedek ise kötü günde geri dönüş noktanız olur.

    Kapanış#

    SQL injection, otuz yılı aşkın süredir bilinen ama hâlâ en sık istismar edilen açıklardan biri. İyi haber şu: temeli doğru attığınızda büyük ölçüde kapanan bir sorun. Kullanıcı verisini daima parametre olarak geçirin, girdileri beklenen biçime göre doğrulayın, uygulamayı en az yetkili bir veritabanı kullanıcısıyla çalıştırın ve bunların üstüne bir WAF katmanı ekleyin. Bu dört adım birlikte uygulandığında, hem otomatik taramalara hem de hedefli denemelere karşı ciddi bir dirence kavuşursunuz.

    Bu katmanları tek tek kurmakla uğraşmak istemiyorsanız, Clou.TR altyapısı işin büyük kısmını sizin için hazır getirir. WAF ve DDoS korumasıyla güçlendirilmiş web hosting ve WordPress hosting paketlerimiz, güncel PHP sürümleri ve sıkılaştırılmış varsayılanlarla gelir. Tam kontrol isteyen ekipler için sanal sunucu ve VDS seçeneklerimizi, günlük yönetim yükünü devretmek isteyenler içinse sunucu yönetimi ve yedekleme hizmetlerimizi inceleyebilirsiniz. Uygulamanızı güvenli bir zemine taşımak için site taşıma ekibimiz de yanınızda. Güvenlik bir ürün değil, katmanlı bir alışkanlıktır; doğru altyapıyla bu alışkanlığı sürdürmek çok daha kolay hâle gelir.

    GüvenlikVeritabanıOWASP

    Uygulamaya geçmeye hazır mısınız?

    NVMe SSD, ücretsiz SSL ve %99.9 uptime garantisiyle Clou.TR hosting ve sunucu çözümleriyle projenizi hayata geçirin.