Birçok yararlı cevap ile ilgili olarak, bu konuya biraz değer katmayı umuyorum.
SQL enjeksiyonu, kullanıcı girişleri (bir kullanıcı tarafından doldurulan ve daha sonra sorguların içinde kullanılan girişler) aracılığıyla yapılabilen bir saldırıdır. SQL enjeksiyon kalıpları doğru sorgu sözdizimidir, ancak bunu çağırabiliriz: kötü nedenlerden dolayı kötü sorgular ve üç güvenlik ilkesini (gizlilik) etkileyen gizli bilgileri (erişim kontrolünü atlayarak) almaya çalışan kötü bir kişi olabileceğini varsayıyoruz. , bütünlük ve kullanılabilirlik).
Şimdi, SQL enjeksiyon saldırıları gibi güvenlik tehditlerini önlemek, soruyu sormak (PHP kullanarak bir SQL enjeksiyon saldırısının nasıl önleneceği), daha gerçekçi olun, veri filtreleme veya giriş verilerini temizleme, içerideki kullanıcı giriş verilerini kullanırken böyledir PHP veya başka bir programlama dili kullanan böyle bir sorgu böyle değildir veya daha fazla insan tarafından hazırlanan ifade veya şu anda SQL enjeksiyon önleme özelliğini destekleyen diğer araçlar gibi modern teknolojiyi kullanması için önerildiği gibi, bu araçların artık mevcut olmadığını düşünüyor musunuz? Başvurunuzu nasıl güven altına alıyorsunuz?
SQL enjeksiyonuna karşı yaklaşımım: veri girişini veritabanına göndermeden önce (herhangi bir sorguda kullanmadan önce) temizlemek.
İçin veri filtreleme (güvenli olmayan verileri güvenli verilere dönüştürme)
PDO ve MySQLi'nin kullanılabilir olmadığını düşünün . Başvurunuzu nasıl güvence altına alabilirsiniz? Beni onları kullanmaya zorlar mısın? PHP dışındaki diğer diller ne olacak? Sadece belirli bir dil için değil, daha geniş sınır için kullanılabileceği için genel fikirler sunmayı tercih ediyorum.
- SQL kullanıcısı (kullanıcı ayrıcalığını sınırlayan): en yaygın SQL işlemleri (SELECT, UPDATE, INSERT) 'dir, o zaman UPDATE'e gerek duymayan bir kullanıcıya neden ayrıcalık verin? Örneğin, giriş ve arama sayfaları yalnızca SELECT kullanıyor, o zaman bu sayfalarda neden yüksek ayrıcalıklara sahip DB kullanıcıları kullanıyorsunuz?
KURAL: tüm ayrıcalıklar için bir veritabanı kullanıcısı oluşturmayın. Tüm SQL işlemleri için, kolay kullanım için düzeninizi (deluser, selectuser, updateuser) gibi kullanıcı adları olarak oluşturabilirsiniz.
En az ayrıcalık ilkesine bakın .
Veri filtreleme: herhangi bir sorgu kullanıcı girişi oluşturmadan önce, doğrulanmalı ve filtrelenmelidir. Programcılar için, her kullanıcı-girdi değişkeni için bazı özellikler tanımlamak önemlidir:
veri türü, veri deseni ve veri uzunluğu . (X ve y) arasındaki bir sayı olan bir alan, tam kural kullanılarak tam olarak doğrulanmalıdır ve dize (metin) olan bir alan için: desen söz konusudur, örneğin, bir kullanıcı adı yalnızca bazı karakterler içermelidir. deyin [a-zA-Z0-9_-.]. Uzunluk (x ve n) arasında değişir ve burada x ve n (tamsayılar, x <= n).
Kural: tam filtreler ve doğrulama kuralları oluşturmak benim için en iyi uygulamalardır.
Diğer araçları kullanın: Burada, hazır bir ifade (parametreli sorgu) ve saklı yordamlar konusunda da aynı fikirdeyim. Buradaki dezavantajlar, bu yolların çoğu kullanıcı için mevcut olmayan gelişmiş becerileri gerektirmesidir. Buradaki temel fikir, SQL sorgusu ile içinde kullanılan veriler arasında ayrım yapmaktır. Her iki yaklaşım da güvensiz verilerle bile kullanılabilir, çünkü buradaki kullanıcı giriş verileri orijinal sorguya (any veya x = x) gibi hiçbir şey eklemez.
Daha fazla bilgi için lütfen OWASP SQL Enjeksiyon Önleme Hile Sayfası'nı okuyun .
Şimdi, ileri düzey bir kullanıcıysanız, bu savunmayı istediğiniz gibi kullanmaya başlayın, ancak yeni başlayanlar için, depolanmış bir prosedürü hızlı bir şekilde uygulayamazlar ve ifadeyi hazırlayamazlarsa, giriş verilerini olabildiğince filtrelemek daha iyidir.
Son olarak, bir kullanıcının kullanıcı adını girmek yerine bu metni aşağıda gönderdiğini düşünelim:
[1] UNION SELECT IF(SUBSTRING(Password,1,1)='2',BENCHMARK(100000,SHA1(1)),0) User,Password FROM mysql.user WHERE User = 'root'
Bu girdi, önceden hazırlanmış herhangi bir ifade ve saklı yordam olmadan erken kontrol edilebilir, ancak kullanıcı tarafında veri filtreleme ve doğrulama işleminden sonra bunları kullanmak üzere güvenli tarafta olmak gerekir.
Son nokta, daha fazla çaba ve karmaşıklık gerektiren beklenmedik davranışları tespit etmektir; normal web uygulamaları için önerilmez.
Yukarıdaki kullanıcı girişinde beklenmeyen davranış SELECT, UNION, IF, SUBSTRING, BENCHMARK, SHA ve root'tur. Bu kelimeler algılandıktan sonra, girdiden kaçınabilirsiniz.
GÜNCELLEME 1:
Bir kullanıcı bu yazının işe yaramaz olduğunu söyledi, tamam! İşte OWASP.ORG sağladığı :
Birincil savunmalar:
Seçenek # 1: Hazırlanan Deyimlerin Kullanılması (Parametrelenmiş Sorgular)
Seçenek # 2: Saklı Yordamların Kullanılması
Seçenek # 3: Kullanıcı Tarafından Verilen Tüm Girdilerden Kaçınma
Ek savunmalar:
Ayrıca Zorla: En Küçük Ayrıcalık
Ayrıca Gerçekleştir: Beyaz Liste Giriş Doğrulaması
Bildiğiniz gibi, bir makaleyi talep etmek geçerli bir argümanla, en az bir referansla desteklenmelidir! Aksi takdirde, bir saldırı ve kötü bir iddia olarak kabul edilir!
Güncelleme 2:
PHP kılavuzundan, PHP: Hazırlanan Bildirimler - Manual :
Kaçış ve SQL enjeksiyonu
Bağlı değişkenler sunucu tarafından otomatik olarak kaçacaktır. Sunucu, kaçan değerlerini uygun yerlerde yürütmeden önce ifade şablonuna ekler. Uygun bir dönüşüm oluşturmak için, bağlı değişken türü için sunucuya bir ipucu verilmelidir. Daha fazla bilgi için mysqli_stmt_bind_param () işlevine bakın.
Sunucudaki değerlerin otomatik olarak kaçması bazen SQL enjeksiyonunu önlemek için bir güvenlik özelliği olarak kabul edilir. Giriş değerlerinden doğru bir şekilde kaçılırsa, hazırlıksız ifadelerle aynı güvenlik derecesi elde edilebilir.
Güncelleme 3:
Hazırlanan bir ifade kullanırken PDO ve MySQLi'nin MySQL sunucusuna sorguyu nasıl gönderdiğini bilmek için test senaryoları oluşturdum:
PDO:
$user = "''1''"; // Malicious keyword
$sql = 'SELECT * FROM awa_user WHERE userame =:username';
$sth = $dbh->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
$sth->execute(array(':username' => $user));
Sorgu Günlüğü:
189 Query SELECT * FROM awa_user WHERE userame ='\'\'1\'\''
189 Quit
MySQLi:
$stmt = $mysqli->prepare("SELECT * FROM awa_user WHERE username =?")) {
$stmt->bind_param("s", $user);
$user = "''1''";
$stmt->execute();
Sorgu Günlüğü:
188 Prepare SELECT * FROM awa_user WHERE username =?
188 Execute SELECT * FROM awa_user WHERE username ='\'\'1\'\''
188 Quit
Hazırlanan bir ifadenin de verilerden kaçtığı açıktır, başka bir şey değildir.
Yukarıdaki açıklamada da belirtildiği gibi,
Sunucudaki değerlerin otomatik olarak kaçması bazen SQL enjeksiyonunu önlemek için bir güvenlik özelliği olarak kabul edilir. Giriş değerlerinden doğru bir şekilde kaçılırsa, hazırlıksız ifadelerle aynı güvenlik derecesi elde edilebilir
Bu nedenle, bu, intval()
herhangi bir sorgu göndermeden önce tamsayı değerleri için veri doğrulamanın iyi bir fikir olduğunu kanıtlar . Ayrıca, sorguyu göndermeden önce kötü niyetli kullanıcı verilerinin engellenmesi doğru ve geçerli bir yaklaşımdır .
Daha fazla ayrıntı için lütfen bu soruya bakın: PDO, MySQL'e ham sorgu gönderirken, Mysqli hazırlanmış sorgu gönderirken her ikisi de aynı sonucu verir
Referanslar:
- SQL Enjeksiyon Hile Sayfası
- SQL Enjeksiyonu
- Bilgi Güvenliği
- Güvenlik İlkeleri
- Veri doğrulama