Soru Uygulama güvenliği için mysql_real_escape_string () ve mysql_escape_string () yeterli mi?


Mysql_real_rescape_string () beni bilgisayar korsanlarına ve SQL saldırılarına karşı koruyacak mı? Bunu sordum çünkü bunların tüm saldırı vektörlerine karşı yardım etmediğini duydum. Uzmanların tavsiyelerini arıyorum.

DÜZENLEME: Ayrıca, LIKE SQL saldırıları hakkında ne dersiniz?


20
2018-03-24 04:23


Menşei


olası kopyası PHP'de dize gönderirken PHP'de htmlspecialchars () kullanarak yasal olmayan karakterlere dikkat etmeli veya regex kullanmalı mıyım? - Your Common Sense
GİBİ saldırıları büyük bir anlaşma değildir. Yanlış kullanılmadığı sürece LIKE'dan zarar gelmez. Sadece yerine LIKE kullanmayın =  ve iyi olacaksın. - Your Common Sense
olası kopyası PHP'de SQL Enjeksiyonunu önlemenin en iyi yolu - tereško
ilgili: Mysql_real_escape_string () etrafında alır SQL enjeksiyon - tereško


Cevaplar:


@Charles son derece doğru!

Kendinizi birden fazla tür için risk altına soktunuz bilinen SQL saldırıları, bahsettiğiniz gibi

  • SQL enjeksiyonu: Evet! Mysql_Escape_String muhtemelen STILL, sorgularınızda PHP değişkenlerini kullandığınız yere bağlı olarak sizi SQL enjeksiyonlarına karşı hassas tutar.

Bunu düşün:

$sql = "SELECT number FROM PhoneNumbers " .
       "WHERE " . mysql_real_escape_string($field) . " = " . mysql_real_escape_string($value);  

Bu şekilde güvenli ve doğru bir şekilde kaçabilir mi? YOK HAYIR! Niye ya? Çünkü bir hacker, bunu hala yapabilir:

Benden sonra tekrar et:

mysql_real_escape_string() sadece değişken veriden kurtulmak içindir DEĞİL Tablo adları, sütun adları ve özellikle LIMIT alanları değil.

  • GİBİ GELİŞTİRME: $ data "$%" olabilir, burada $ data "%" olabilir ve TÜM kayıtları geri döndürür ... çok iyi olabilir Bir güvenlik istisnası ... sadece bir kredi kartının son dört hanesine göre bir Arama hayal edin ... OOP'lar! Artık bilgisayar korsanları sisteminizde her kredi kartı numarasını alabilir! (BTW: Tam kredi kartlarını saklamak neredeyse hiç önerilmez!)

  • Charset Exploits: Hayranların söyledikleri önemli değil, Internet Explorer yine, 2011'de, Karakter Seti Exploits'e karşı savunmasız ve bu Eğer HTML sayfanızı doğru olarak, <meta name="charset" value="UTF-8"/>! Bu saldırılar, hacker'lara düz SQL enjeksiyonları kadar kontrol edebildikleri için ÇOK kötüdür: ör. tam.

Tüm bunları göstermek için bazı örnek kod:

// Contains class DBConfig; database information.
require_once('../.dbcreds');                       

$dblink = mysql_connect(DBConfig::$host, DBConfig::$user, DBConfig::$pass);
mysql_select_db(DBConfig::$db);
//print_r($argv);

$sql = sprintf("SELECT url FROM GrabbedURLs WHERE %s LIKE '%s%%' LIMIT %s",
               mysql_real_escape_string($argv[1]),
               mysql_real_escape_string($argv[2]),
               mysql_real_escape_string($argv[3]));
echo "SQL: $sql\n";
$qq = mysql_query($sql);
while (($data = mysql_fetch_array($qq)))
{
        print_r($data);
}

Çeşitli girdiler geçtiğinde bu kodun sonuçları aşağıdadır:

$ php sql_exploits.php url http://www.reddit.com id
SQL generated: SELECT url FROM GrabbedURLs 
               WHERE url LIKE 'http://www.reddit.com%'
               ORDER BY id;
Returns: Just URLs beginning w/ "http://www.reddit.com"

$ php sql_exploits.php url % id
SQL generated: SELECT url FROM GrabbedURLs 
               WHERE url LIKE '%%' 
               ORDER BY id;
Results: Returns every result Not what you programmed, ergo an exploit --

$ php sql_exploits.php 1 = 1   'http://www.reddit.com'id Sonuçları:   Her sütunu ve her sonucu döndürür.

Sonra GERÇEKTEN kötü LIMIT istismarlar vardır:

$ php sql_exploits.php url 
> 'http://www.reddit.com'
> "UNION SELECT name FROM CachedDomains"
Generated SQL: SELECT url FROM GrabbedURLs 
               WHERE url LIKE 'http://reddit.com%' 
               LIMIT 1 
               UNION
               SELECT name FROM CachedDomains;
Returns:  An entirely unexpected, potentially (probably) unauthorized query
          from another, completely different table. 

SQL'in saldırılarda olup olmadığını anlamazsınız. Bunun gösterdiği şey, mysql_real_escape_string () is kolayca en habersiz hackerlar tarafından bile atlatıldı. Bunun nedeni REAKTİF bir savunma mekanizmasının olmasıdır. Veritabanında sadece çok sınırlı ve BİLİNCİ faydaları giderir.

Kaçan tüm veritabanları güvenli hale getirmek için yeterli olmayacaktır. Aslında, her BİLİNCİ istismarına açıkça REACT uygulayabilirsiniz ve gelecekte kodunuz büyük olasılıkla gelecekte ortaya çıkacak saldırılara karşı savunmasız kalacaktır.

Doğru ve sadece (gerçekten) savunma bir YARATICI olan: Hazırlanmış İfadeleri Kullanın. Hazırlanan ifadeler, SADECE geçerli ve PROGRAMLANMIŞ SQL yürütülmesi için özel olarak tasarlanmıştır. Bu, doğru bir şekilde yapıldığında, beklenmedik SQL'in gerçekleştirilebilme olasılığının dramatik olarak azaldığı anlamına gelir.

Teorik olarak, hazırlanan mükemmel ifadeler, DATABASE SERVERS THEMSELVES tarafından işlenen SERVER SIDE tekniği ve programlama dili ile arayüzleşen kütüphaneler oldukları için bilinen ve bilinmeyen ALL saldırılarına karşı geçirimsiz olacaktır. Bu nedenle, HER YERDE HERHANGİ HERHANGİ BİLİNEN HACK karşısına, en düşük düzeyde korunacaksınız.

Ve daha az kod:

$pdo = new PDO($dsn);

$column = 'url';
$value = 'http://www.stackoverflow.com/';
$limit = 1;

$validColumns = array('url', 'last_fetched');

// Make sure to validate whether $column is a valid search parameter.
// Default to 'id' if it's an invalid column.
if (!in_array($column, $validColumns) { $column = 'id'; }


$statement = $pdo->prepare('SELECT url FROM GrabbedURLs ' .
                           'WHERE ' . $column . '=? ' .
                           'LIMIT ' . intval($limit));
$statement->execute(array($value));
while (($data = $statement->fetch())) { }

Şimdi bu o kadar da zor değildi? Ve Onun yüzde kırk yedi daha az kod (195 chars (PDO) vs 375 chars (mysql_) Ben buna "kazandık" diyorum.

DÜZENLEME: Tüm bu tartışmaları ele almak için bu cevabı karıştırdım, daha önce söylediğim şeyi tekrar etmeme izin verin:

Hazırlanan ifadelerin kullanılması, kişinin koruyucu önlemlerin alınmasını sağlar.   SQL sunucusunun kendisi ve dolayısıyla   sen şeylerden korunuyorsun   SQL sunucusu insanlar hakkında biliyor. Çünkü   Bu ekstra koruma seviyesinin   sadece kullanarak daha güvenli   kaçmak, ne kadar titiz olursa olsun.


14
2018-03-25 14:07



ve hazırlanmış ifadeler örneğiniz çok gülünç :) Şans eseri koştunuz mu? - Your Common Sense
İçin veriler LIKE İfade, kaçarak da ek olarak temizlenmelidir % ve _. - zerkms
@Theodore R. Smith: "Tüm sızan veritabanları güvenli hale getirmek için ASLA olmayacak." --- iyi yapabilir misin kanıtlamak O? Çok fazla teori ve yüksek sesli kelimeler olmadan. Mysql_real_escape_string kullanan bir kod oluşturuyorum ve korunan verileri almak için herhangi bir sql enjeksiyonu kullanıyorsunuz. Tamam? Sadece felsefe olmaktan çok, gerçek ve daha fazlasını yapmak için yeterli yetkin var mı? - zerkms
ne yazık. Bu noktayı almazsın. "kodlayıcı" demek değil. "LANGUAGE OPERATOR" anlamına geliyor. Operatör, tüm tablodan çok sayıda sonuç döndürmek anlamına geliyordu, bu yüzden, bir kodlayıcı bunu BEKLİYOR. Sadece bir eşleşme bekleniyorsa, NO LIKE kullanılmalıdır. bu kadar. ve mysql_real_escape_string (), VARIABLE ile değil, INT türü ile size yardımcı olmaz. Daha fazla öğrenmeyi reddediyorsun, beni üzüyor. Muhtemelen bu yüzden hala "araştırmanızı" çok önemsiyorsunuz ve dinlemek için kendinizle gurur duyuyorsunuz. - Your Common Sense
ve yanlış şekilde yanlış düzeltildi. PDO limit parametreleri ile tamam, bunun için hazırlanmış deyimi kullanabilir (ve yapmalı). Aslında, sorgu montaj kodunuz normal mysql birinden daha iyi görünmüyor :) - Your Common Sense


Yok hayır!


Önemli güncelleme: Test ettikten sonra Col. Shrapnel tarafından sağlanan olası istismar kodu ve MySQL 5.0.22, 5.0.45, 5.0.77 ve 5.1.48 sürümlerini gözden geçiriyor gibi görünüyor. GBK karakter kümesi ve muhtemelen başkaları MySQL sürümü ile birlikte 5.0.77'den küçük eğer kodunuzu savunmasız bırakabilirseniz bir tek kullanım SET NAMES spesifik kullanmak yerine mysql_set_charset/mysqli_set_charset fonksiyonlar. Çünkü bunlar sadece PHP 5.2.x'te eklendi. Eski PHP ve eski MySQL'in bir araya gelmesi olası bir SQL Injection güvenlik açığı verebilir.Güvende olduğunu düşündüysen ve her şeyi doğru bir şekilde yaptıysan bile.


olmadan karakter kümesinin ayarlanması ile bütünlüğünde mysql_real_escape_stringKendinizi eski MySQL sürümleriyle mümkün olan belirli bir karakter kümesine karşı savunmasız bulabilirsiniz. Önceki araştırmalar hakkında daha fazla bilgi.

Mümkünse kullanın mysql_set_charset. SET NAMES ... olduğu değil MySQL'in etkilenen bir sürümünü kullanıyorsanız, bu özel istismara karşı korunacak kadar 5.0.22 5.0.77).


8
2018-03-24 05:11



+1 Bu doğru bir cevaptır ve bir ek istismar ve bunların nasıl düzeltileceğini belirtir. Bilinen tüm SQL istismarları için aşağıdaki detaylı cevabımı inceleyin. mysql_real_escape_string Her biri için yeterli ve güvenli ve kolay bir alternatif: PDO hazırlanmış ifadeler. - Theodore R. Smith
-1 tüm bu saçmalıkların yalnızca son derece nadir kodlama kullanıldığında, ancak utf ve tek baytlı kodlamalar için herhangi bir zarara yol açmayacağı anlamına gelmediği için. - Your Common Sense
@Col, son derece nadir problemin açıklamaının postayla bağlantılı olduğunu söyledi ve ben did MySQL'in eski bir sürümüyle bağlantılı çok özel bir istismar olduğunu açıklar. - Charles
lol, noktayı bile almadın. SET İSİMLERİ herhangi bir mysql sürümü ile hala yeterli değil - Your Common Sense
@Col, lütfen geçtiğinde bir sorgu ve kullanıcı girişi sağlayın mysql_real_escape_string kullandıktan sonra SET NAMES bu, MySQL sürümlerindeki güvenlik açığını gösterir daha yeni 5.0.22'den. Ya da başka bir yol koymak, koymak ya da susturmak. “Anlama” ve “noktayı kaçırma” uğruna insanlara tecavüz etmeyi sürdürüyorsun, ama aslında hiç kimsenin görmediğini bilemezsiniz. Bu senin şansın. - Charles


Evet. Eğer unutmayacaksan:

  1. İle dize veri kaçış mysql_real_rescape_string()
  2. Sayıları açık bir şekilde sayılara dökün (ör: $id = (int)$_GET['id'];)

o zaman korunuyorsun.


7
2018-03-24 04:26



+1 Ve 2'yi unutursanız ve kullanın mysql_real_escape_string(), her zaman onları alıntı :) - alex
@alex bazen onları tam olarak yapamazsın - Your Common Sense
-1 Bu çok tehlikeli bir tavsiye. Ben demek istemiyorum - muhtemelen daha iyi bir şey bilmiyorsunuz - ama SQL güvenlik için sadece giriş değişkenlerinden kaçmaktan çok daha fazlası var ... ve aşağıda daha ayrıntılı olarak tarif ettiğim çok daha kolay ve daha güvenli bir sistem var. . - Theodore R. Smith
Bu herif dostunun sadece bir iyi noktası var: tanımlayıcılar. - Your Common Sense
@Theodore R. Smith: peki, pratiğimde, kullanıcıların girişinden asla alan veya masa isimlerini almıyorum. Evet, sorgu girdiye bağlı olabilir, ancak veriyi hiçbir zaman SQL'e yerleştirmem. Yani, bence tavsiye hala iyi ve seksi. - zerkms


Ben şahsen tercih ederim hazırlanan ifadeler:

<?php
$stmt = $dbh->prepare("SELECT * FROM REGISTRY where name = ?");
if ($stmt->execute(array($_GET['name']))) {
  while ($row = $stmt->fetch()) {
    print_r($row);
  }
}
?>

Birinden birini kullanırken kaçırılan bir veya başka bir belirli değişkeni gözden kaçırmak oldukça kolay olurdu. *escape_string() işlevler, ancak tüm sorgularınız hazır ifadeler içeriyorsa, hepsi iyi durumdadır ve enterpolasyonlu değişkenlerin kullanımı bir boğaz başparmak gibi göze çarpacaktır.

Fakat bu, uzak istismarlara karşı savunmasız kalmamanız için yeterli olmaktan çok uzaktır: &admin=1 ile GET veya POST Birisinin yönetici olduğunu belirtmek için istekte bulunursanız, kullanıcılarınızın her biri ayrıcalıklarını iki veya üç saniyelik bir çabayla kolayca yükseltebilir. Bu sorunun her zaman bu kadar açık olmadığını unutmayın :) ancak bu, kullanıcı tarafından sağlanan girdiye güvenmenin sonuçlarını çok açıklamak için kolay bir yoldur.


3
2018-03-24 04:29





Bunun yerine hazırlanmış ifadeleri / parametreli sorguları kullanmalısınız. Fikir, veritabanına yer tutucularla bir sorgu vermenizdir. Veritabanına veriyi verin ve hangi yer tutucunun söz konusu verilerle değiştirileceğini söyleyin ve veritabanı geçerli olduğundan emin olun ve yer tutucunun taşmasına izin vermez (örneğin, geçerli bir sorguyu sonlandıramaz ve sonra ekleyemezsiniz). kendi - ortak bir saldırı).


2
2018-03-24 04:30



+1 Bu doğru bir cevaptır ve SQL yöntemlerinin nasıl önleneceğine ilişkin birincil yöntemi adlandırır. Bilinen tüm SQL istismarları için aşağıdaki detaylı cevabımı inceleyin. mysql_real_escape_string Her biri için yetersizdir ve @ AgentConundrum'un güvenli ve kolay alternatifidir: PDO tarafından hazırlanmış ifadeler. - Theodore R. Smith