En güvenilir yol, her zaman parametreli sorgular veya hazırlanan ifadeler (prepared statements) kullanmaktır, kullanıcı değerlerinin basit dize birleştirmesiyle sorgular oluşturmamak gerekir.
Daha karmaşık senaryolar için (prosedürler içinde dinamik SQL) özel kaçış mekanizmaları ve parametrelerin beyaz listeye alınması (sıkı filtreleme) uygulanmalıdır.
cursor.execute('SELECT * FROM users WHERE login = %s', [login])
EXECUTE format('SELECT * FROM %I WHERE id = $1', tablename) USING id;
Burada %I sadece tablo/kolon adlarını güvenli bir şekilde ekler.
Aşağıdaki yaklaşım sayı eklenirken güvenli midir?
EXECUTE 'SELECT * FROM users WHERE id = ' || user_input;
HAYIR! Sayı bekleseniz bile, kötü niyetli biri şu kodu geçirebilir:
1; DROP TABLE users; — sorgu çalıştırılacaktır. Bu nedenle her zaman yer tutucular ve giriş parametrelerinin türlerinin açıkça kontrol edilmesi gerekmektedir.
Hikaye 1
Çalışanlar için arama formu, uygulama tarafında dizeleri birleştirerek WHERE koşulları oluşturuyordu. Kötü niyetli biri: ' OR 1=1 -- girdi, bu da tüm çalışanların verilerini ortaya çıkardı. Daha sonra yine benzer bir yaklaşım kullanılarak veri bölümü silindi. Sonuç: anlamlı parametrelerin birleştirilmesi her zaman risklidir.
Hikaye 2
İdari rapor seçme arayüzünde, tablo adı kullanıcı alanından alınarak SQL sorgusuna ekleniyordu. Kullanıcı geçersiz bir isim ekleyerek sistem tablolarına erişim sağladı. Daha sonra yalnızca sıkı belirlenmiş isimler (beyaz liste) kullanmaya izin verildi.
Hikaye 3
E-ticaret projesinde dinamik sıralama sırasında kullanıcılar GET parametresi ile alan adını geçiriyordu. Bir hacker price; DELETE FROM orders; -- ekledi ve bu, tüm siparişlerin kaybıyla sonuçlandı. Geçerli kolon adlarının filtrelenmesi ve parametreli sorguların kullanılması sorunu çözdü.