Saldırı altında mısınız? Olay müdahalesi için bize ulaşın

Web güvenliği

Birleştirilmiş SQL sorgularını bulun, parametreyle değiştirin

Uygulama kodu ve stored procedure'lerdeki birleştirilmiş SQL'i bulma, bind edilen parametrelerle değiştirme ve veritabanı yetkilerini kısıtlama.

Diğer diller:EnglishDeutschFrançaisEspañolItalianoPolskiNederlandsEesti

İllüstrasyon: Birleştirilmiş SQL sorgularını bulun, parametreyle değiştirin

Güvenilmeyen değerlerle string birleştirilerek oluşturulan her SQL ifadesine enjeksiyon yapılabilir ve çözüm her dilde aynıdır: SQL'i sabit tutun, değerleri parametre olarak bağlayın (bind). OWASP Query Parameterization Cheat Sheet, SQL injection'ı OWASP Top 10:2025 içinde A05:2025-Injection kategorisine yerleştirir ve onu en tehlikeli web zafiyetlerinden biri olarak niteler.

Birleştirme neden yetersiz kalır

SQL, kontrol düzlemi ile veri düzlemi arasında gerçek bir ayrım yapmaz. Saldırgan bir girdiye meta karakter yerleştirir ve daha önce var olmayan SQL komutları ortaya çıkar. SQL injection hakkındaki OWASP topluluk sayfası, birleştirmeyle oluşturulmuş bir C# sorgusunu gösterir:

string query = "SELECT * FROM items WHERE owner = '"
    + userName + "' AND itemname = '"
    + ItemName.Text + "'";

Saldırgan ürün adı olarak name' OR 'a'='a girerse koşul her zaman doğru olur. Sorgu, sahibi kim olursa olsun items tablosundaki tüm satırları döndürür. Veritabanının özelliklerine ve yetkilere bağlı olarak aynı açık verileri değiştirmek, dosyaları etkilemek veya işletim sistemi komutları çalıştırmak için de kullanılabilir.

Değerin kaynağı fark etmez. Veri bir HTTP isteğinden, başka bir servisten ya da daha önce saklanmış verilerden gelse de aynı kontroller geçerlidir.

String ile oluşturulan sorguları bulun

SQL anahtar sözcüklerinin birleştirme veya biçimlendirme ifadelerinin yanında geçtiği yerleri grep ile aramaya başlayın. Bu kalıplar kaba bir ilk taramadır, tarayıcı yerine geçmez. Çok sayıda yanlış pozitif üretirler ve birden çok satıra bölünmüş sorguları kaçırırlar.

# concatenation (Java, C#, JavaScript, PHP uses "." instead of "+")
grep -rnEi "(select|insert into|update|delete from)[^;]*[\"'] *\+" src/
# Python f-strings and .format()
grep -rnEi "f[\"'](select|insert|update|delete)|(select|insert|update|delete).*\.format\(" .
# JavaScript template literals
grep -rnEi '`(select|insert|update|delete)[^`]*\$\{' src/
# sprintf-style formatting
grep -rnEi "sprintf\(.*(select|insert|update|delete)" .

Her sonucu okuyun ve güvenilmeyen değerlerin birleştirilmek yerine parametre olarak bağlandığını doğrulayın. Ardından grep'in genellikle atladığı yerlere bakın:

  • ORM sorgu string'leri. Değerler bağlanmak yerine sorgu string'ine birleştirildiğinde Hibernate sorguları da savunmasız olabilir.
  • Stored procedure'ler. SQL'i veritabanında tutarlar ancak kendiliğinden güvenli değildirler. OWASP, usr ve itm değerlerini bir sorgu string'ine birleştiren bir PL/SQL prosedürünü gösterir ve bunun "ilk örnekte gösterilen SQL injection saldırısına karşı aynı şekilde savunmasız" olduğunu söyler. Çağrının argümanlarını bağlamak çağrıyı korur, prosedür içinde oluşturulan dinamik SQL'i korumaz.
  • İstemci tarafı parametreleştirme. Birçok istemci tarafı kütüphane sorguları string birleştirmeyle oluşturur ve ham sorguyu sunucuya gönderir. Parametreleştirmenin sunucu tarafında yapıldığını doğrulayın.
  • Dinamik tanımlayıcılar ve sıralama yönleri. Bunlar parametre olarak bağlanamaz, bu yüzden parametreleştirme taramasından sonra birleştirmenin hayatta kaldığı yerler buralardır.

Sonra test edin. OWASP Web Security Testing Guide, blind ve out-of-band teknikler dahil olmak üzere manuel ve otomatik test için SQL injection testleri içerir. İncelemenizin gözden kaçırdıklarını dışarıdan kontrol etmek ise sızma testinin işidir.

Parametrelerle değiştirin

SQL yapısını veri değerlerinden ayrı tanımlayın, ardından değerleri veritabanı API'si üzerinden bağlayın. Aşağıdaki örnek, temizleme ve hata yönetimi çıkarılmış hâliyle OWASP SQL Injection Prevention Cheat Sheet kaynağından alınmıştır:

String query = "SELECT account_balance FROM user_data WHERE user_name = ?";
PreparedStatement statement = connection.prepareStatement(query);
statement.setString(1, customerName);
ResultSet results = statement.executeQuery();

tom' or '1'='1 gibi bir değer artık eşleştirilecek düz kullanıcı adı olarak ele alınır. Güvenilmeyen bir değeri sorgu hazırlanmadan önce sorguya birleştirmek korumayı geçersiz kılar.

ORM kullanırken de sorgu string'i içinde bağlama yapın. OWASP örnekleri HQL'de FROM Inventory i WHERE i.productDescription = :productDescription şeklinde adlandırılmış bir parametre kullanır ve değeri setParameter ile iletir.

Stored procedure'ler içindeki dinamik SQL için bind variable kullanın. Oracle PL/SQL'de bu, USING ile birlikte EXECUTE IMMEDIATE demektir. SQL Server'da ise bildirilmiş bir parametre listesiyle sp_executesql kullanmak anlamına gelir. Dinamik SQL içermeyen prosedürler için özel bir şey gerekmez, çünkü parametreleri zaten bağlıdır.

Parametre bağlama, bir değerin SQL sözdizimini değiştirmesini engeller. Çağıranın ilgili hesaba erişme hakkı olup olmadığına karar vermez, bu nedenle yetkilendirme kontrollerinizin yerinde kalması gerekir.

Parametrelerin kapsamadığı durumlar

Parametre işaretleri veri değerlerinin yerini tutar. Tablo adlarının, sütun adlarının ya da ASC ve DESC gibi anahtar sözcüklerin yerini tutamazlar. Kullanıcıların seçim yapması gerektiğinde seçimi uygulamanın sahip olduğu küçük bir token kümesine eşleyin ve bilinmeyen her şeyi reddedin. Önce:

String query = "SELECT id, name FROM items ORDER BY name " + sortParam;

Sonra:

Map<String, String> directions = Map.of("asc", "ASC", "desc", "DESC");
String direction = directions.get(sortParam);
if (direction == null) {
    throw new IllegalArgumentException("Unknown sort direction");
}
String query = "SELECT id, name FROM items ORDER BY name " + direction;

Sorguya eklenen metin artık her zaman iki sabit değerden biridir, kullanıcının gönderdiği şey değil. Aynı sorgudaki her veri değerini, tür, uzunluk veya biçim kontrollerinden geçse bile bağlamaya devam edin.

Manuel escape yöntemine başvurmayın. Bu yöntem SQL lehçesine ve yapılandırmaya bağlıdır: örneğin MySQL'in NO_BACKSLASH_ESCAPES modu ters eğik çizgi ile escape'i devre dışı bırakır. OWASP, escape'i kesinlikle önerilmeyen bir yöntem olarak işaretler ve deny list'leri açıklarla dolu olarak tanımlar.

Hasarı sınırlayın

En az yetki ilkesi SQL injection'ı önlemez. Saldırganın bir veritabanı hesabı üzerinden neler yapabileceğini sınırlar, bu yüzden parametrelerle birlikte uygulayın.

  • Sıfır yetkiden başlayın ve her uygulama hesabının ihtiyaç duyduğu hakları ekleyin. Geniş bir yetkiden nelerin alınacağını belirlemeye çalışmak, hakların gözden kaçmasının yoludur.
  • Uygulama hesabına DBA veya admin erişimi vermek olağan kestirmedir, çünkü her şey "sorunsuz çalışır". OWASP bunu çok tehlikeli olarak niteler.
  • Bir giriş sayfasının kullanıcı adı ve parola alanlarına okuma erişimine ihtiyacı vardır, yazma erişimine ihtiyacı yoktur. Bir kayıt sayfasının ise insert yetkisine ihtiyacı vardır. Bu ayrım ancak ikisi farklı veritabanı kullanıcıları kullanıyorsa uygulanabilir, bu yüzden her web uygulamasına kendi kullanıcısını verin.
  • Saldırganların aşırı yetkili bir hesabı kötüye kullanmak için injection'a ihtiyacı yoktur. Bir parametreyi yasal bir değerden, kendilerinin yetkili olmadığı ama uygulamanın yetkili olduğu bir değere çevirebilirler. Bu yüzden sorgular temiz olsa bile dar yetkiler yardımcı olur.
  • Bir view, bir hesabın ihtiyaç duyduğu alanları tek başına sunabilir. Bunun için SELECT yetkisi tabloya değil view'a verilir. Önce veritabanınızın kurallarını kontrol edin: PostgreSQL altta yatan tablo erişimini normalde view sahibinin yetkileriyle denetler. View'lara yönelik sorgularda da parametre gerekir.
  • İşletim sistemi hesabı da önemlidir. DBMS'i root veya system olarak çalıştırmayın. OWASP, MySQL'in Windows'ta varsayılan olarak system olarak çalıştığını not eder.

Nereden başlamalı

  1. SQL oluşturan her yeri listeleyin: uygulama kodu, ORM sorgu string'leri ve dinamik SQL kullanan stored procedure'ler. İlk tarama olarak yukarıdaki grep kalıplarını çalıştırın.
  2. Birleştirilmiş değerleri sunucu tarafında bağlanan parametrelerle değiştirin ve prosedürler içindeki dinamik SQL'i bind variable'larla yeniden oluşturun.
  3. Dinamik tablo, sütun ve sıralama seçimlerini bilinmeyen girdiyi reddeden sabit eşlemelerle değiştirin.
  4. Veritabanı hesaplarını denetleyin. Uygulama hesaplarından DBA ve admin haklarını kaldırın, her uygulamaya kendi kullanıcısını verin ve salt okunur erişimi dar yetkilere ya da view'lara taşıyın.
  5. Web Security Testing Guide'ın SQL injection testlerini sonuç üzerinde çalıştırın veya değişiklikleri incelemesi için güvenli yazılım geliştirme ekibimizden destek isteyin.

Nasıl yardımcı olabiliriz

Sızma testi

Ağlarınıza, uygulamalarınıza ve çalışanlarınıza gerçek bir saldırgan gibi saldırır, her açığı nasıl kapatacağınızı gösteririz.

Bize yazın
AngelForce ekibi

Bu yazıyı AngelForce ekibi hazırladı: Avrupa genelindeki kurumların sistemlerini test eden, izleyen ve koruyan; CEH, LPT Master ve CISA sertifikalı güvenlik danışmanları.

Aşağıda listelenen herkese açık kaynaklardan yapay zekâ desteğiyle yazıldı ve yayından önce AngelForce ekibi tarafından incelendi.

Kaynaklar

  1. cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html
  2. cheatsheetseries.owasp.org/cheatsheets/Query_Parameterization_Cheat_Sheet.html
  3. community.owasp.org/attacks/SQL_Injection

Web güvenliği hakkında yazılar

Neyi korumanız gerektiğini anlatın

Altyapınızı ve hedefinizi kısaca yazın, size e-postayla dönelim.

Bize yazın
info@angelforce.eu +372 5705 2044

AngelForce OÜ · Tallinn, Estonya