DB'ye bağlanmadan mysql_real_escape_string'e alternatif


91

Veritabanına bağlanmadan mysql_real_escape_string gibi davranan bir işleve sahip olmak istiyorum, çünkü bazen DB bağlantısı olmadan kuru test yapmam gerekiyor. mysql_escape_string kullanımdan kaldırılmıştır ve bu nedenle istenmeyen bir durumdur. Bulgularımdan bazıları:

http://www.gamedev.net/community/forums/topic.asp?topic_id=448909

http://w3schools.invisionzone.com/index.php?showtopic=20064



1
+1 MySQL sınıfını kendim yazıyorum ve parametre bağlama amacıyla mysql_real_escape_string () kullanıyorum. Tüm hosting desteklemediği için mysqli kullanmaktan kaçınıyorum. Ayrıca çok dosyalı ve çok sınıflı kitaplıktan da kaçınıyorum. İhtiyacım olan şey sadece düzgün ve temiz bir tek Sınıf. Teşekkür ederim!
Viet

Benim için de +1. Kullanım durumum, SQL parçalarını API aracılığıyla uzak SugarCRM örneğine göndermem gereken bir SugarCRM APi. Ne kadar kötü olsa da, onunla çalışmam gereken şey bu (gidip bazı SugarCRM geliştirici kafalarını bir araya getirin). API kullanan ve SugarCRM örneğinin arkasındaki veritabanından tamamen ayrı olan uygulamada SQL'deki dizelerden çıkış yapmam gerekiyor.
Jason

Yanıtlar:


76

DB bağlantısı olmadan bir dizeden güvenli bir şekilde çıkmak imkansızdır. mysql_real_escape_string()ve hazırlanmış deyimler, uygun karakter setini kullanarak dizeden kaçabilmeleri için veritabanına bir bağlantıya ihtiyaç duyar - aksi takdirde çok baytlı karakterler kullanılarak SQL enjeksiyon saldırıları hala mümkündür.

Yalnızca test yapıyorsanız, o zaman kullanabilirsiniz mysql_escape_string(), SQL enjeksiyon saldırılarına karşı% 100 garantili değildir, ancak bir DB bağlantısı olmadan daha güvenli bir şey oluşturmak imkansızdır.


1
+1 Not için teşekkürler. Çok baytlı karakterler kullanarak SQL enjeksiyon saldırılarına karşı nasıl test yapacağımdan pek emin değilim.
Viet

2
Güncellemem için bazı eski kodlar verildi. mysql_escape_stringBağlantı olmadan kullanıyor (hala nedenini anlamaya çalışıyor). Bu işlev kullanımdan kaldırıldığından, onu nasıl değiştirebileceğimi merak ediyorum. Bir bağlantı açmadan, onun yerine geçen işlevde "uygun karakter kümesini" belirtmek kesinlikle mantıklı görünüyor.
JohnK

3
İmkansız mı? Mysql_real_escape_string, el ile eşdeğer bir işleve aktarılabilen yapılandırma verileri olmayan veritabanı bağlantısından ne alır? Düzenleme: Sadece aşağıyı okuyun, MySQL içinde bir kitaplık işlevi çağırır, bu nedenle PHP dışında gerçekleşen bazı işlemler vardır. Hala taşınabilir olabilir, ancak güncel tutmak başlı başına bir proje olacaktır.
Jason

2
Ya DB karakter kümesi önceden biliniyorsa?
jchook

7
Evet, karakter setini biliyorsanız, kaçmayı bağlantı olmadan yapmayı ne engelliyor?
Johan

67

Eh, mysql_real_escape_string işlevi referans sayfasına göre: "mysql_real_escape_string (), MySQL'in aşağıdaki karakterlerden kaçan mysql_real_escape_string kitaplık işlevini çağırır: \ x00, \ n, \ r, \, '," ve \ x1a. "

Bunu akılda tutarak, gönderdiğiniz ikinci bağlantıda verilen işlev tam olarak ihtiyacınız olanı yapmalıdır:

function mres($value)
{
    $search = array("\\",  "\x00", "\n",  "\r",  "'",  '"', "\x1a");
    $replace = array("\\\\","\\0","\\n", "\\r", "\'", '\"', "\\Z");

    return str_replace($search, $replace, $value);
}

6
Teşekkürler. Başka bir şey öneririm: function escape ($ aQuery) {return strtr ($ aQuery, array ("\ x00" => '\ x00', "\ n" => '\ n', "\ r" => '\ r', '\\' => '\\\\', "'" => "\'", '"' => '\"', "\ x1a" => '\ x1a')) ; }
Viet

1
neden \ x1a \\ x1a yerine \\\ x1a ile değiştiriliyor? Bu bir yazım hatası mı?
Michael Z

16
-1 Bu son derece tehlikelidir. Veritabanı bağlantısı çok baytlı bir karakter kümesi kullanıyorsa, bunun gibi basit ve tek tek değiştirmeler veri bozulmasına (karakterlerin kaçması / alıntılanması dahil) yol açabilir - bu kötü niyetli bir saldırgan tarafından keyfi SQL enjekte etmek için kasıtlı olarak kullanılabilir.
eggyal

Karakter setlerini yanlış anlarsanız, bu tehlikeli olabilir. Çok baytlı karakter kümeleri için, mysql kullanıyorsa, birisi \\ 'yi iptal etmek için bir bayt koyabilir. Multiebyte karakter kümeleri genellikle \\ for mysql dahil olmak üzere herhangi bir şeyi ikinci bayt olarak alabilir, bunu bağımsız bir \\ olarak görmez, ancak çok baytlı karakterin bir parçasıdır. UTF8 ile ne olacağı hakkında hiçbir fikrim yok. Umarım [0xB0, '\\'] geçersiz bir bayta \\ isabet ettiğinde, onu yutmak yerine durur ve o baytla yeniden başlar.
jgmjgm

1
Karakter setinin utf8 olduğunu bilirsem, bunu yapmak için kullanmak mb_strpos()(ve mb_substr()buna benzer bir davranış oluşturmak substr_replace()) güvenli midir?
SOFe

28

Diğer cevabımın tam tersine, bu aşağıdaki işlev muhtemelen çok baytlı karakterlerle bile güvenlidir.

// replace any non-ascii character with its hex code.
function escape($value) {
    $return = '';
    for($i = 0; $i < strlen($value); ++$i) {
        $char = $value[$i];
        $ord = ord($char);
        if($char !== "'" && $char !== "\"" && $char !== '\\' && $ord >= 32 && $ord <= 126)
            $return .= $char;
        else
            $return .= '\\x' . dechex($ord);
    }
    return $return;
}

Benden daha bilgili birinin bana yukarıdaki kodun neden çalışmayacağını söyleyebileceğini umuyorum ...


+1 Ekstra çabanız için teşekkürler. Çoklu bayt ile ilgili SQL enjeksiyonları hakkında daha fazla bilgi edinmek için etrafta dolaşıyorum.
Viet

Sanırım $ return. = '\ X' olmalı. dechex ($ ord); bunun yerine
Viet

1
Genel bir kural olarak, tek tırnaklı dizelerde bile '\\' kullanmayı tercih ederim, çünkü dikkatli değilseniz tek bir '\' sonraki karakteri etkileyebilir. Muhtemelen yine OKB oluyorum.
çok fazla php

1
Bu işlev, mysql kaçış kurallarına uymaz ve veri bütünlüğünün kaybolmasına neden olur. "MySQL, Tablo 9.1," Özel Karakter Kaçış Dizileri "içinde gösterilen kaçış dizilerini tanır. Diğer tüm kaçış dizileri için ters eğik çizgi göz ardı edilir. Yani, kaçan karakter, öncelenmemiş gibi yorumlanır. Örneğin," \ x " sadece "x". " - dev.mysql.com/doc/refman/5.6/en/…
velcrow

2
\ XAA aslında bir MySQL dizgisindeki "xAA" metninden daha fazla bir şey ifade ediyor mu? Belgeler, \ x'in özel bir anlamı olmadığını söylüyor, bu yüzden \ yok sayılacak. dev.mysql.com/doc/refman/5.0/en/string-literals.html
Jason

6

Daha fazla araştırmadan şunu buldum:

http://dev.mysql.com/doc/refman/5.1/en/news-5-1-11.html

Güvenlik Düzeltmesi:

Çok baytlı kodlama işlemede bir SQL enjeksiyon güvenlik açığı bulundu. Hata sunucudaydı, mysql_real_escape_string () C API işleviyle kaçan dizeyi yanlış bir şekilde ayrıştırıyordu.

Bu güvenlik açığı, OSDB konsorsiyumunun projeler arası güvenlik işbirliğinin bir parçası olarak Josh Berkus ve Tom Lane tarafından keşfedildi ve bildirildi. SQL yerleştirme hakkında daha fazla bilgi için lütfen aşağıdaki metne bakın.

Tartışma. Çok baytlı kodlama işlemede bir SQL enjeksiyon güvenlik açığı bulundu. Bir SQL enjeksiyon güvenlik açığı, bir kullanıcı veri tabanına eklenmek üzere veri sağladığında, kullanıcının sunucunun yürüteceği verilere SQL ifadeleri enjekte edebildiği bir durumu içerebilir. Bu güvenlik açığıyla ilgili olarak, karakter kümesi farkında olmadan kaçış kullanıldığında (örneğin, PHP'de addslashes ()), bazı çok baytlı karakter kümelerinde (örneğin, SJIS, BIG5 ve GBK) kaçmayı atlamak mümkündür. Sonuç olarak, addslashes () gibi bir işlev, SQL enjeksiyon saldırılarını önleyemez. Bunu sunucu tarafında düzeltmek imkansız. En iyi çözüm, uygulamaların mysql_real_escape_string () gibi bir işlev tarafından sunulan karakter kümesine duyarlı kaçmayı kullanmasıdır.

Ancak, MySQL sunucusunun mysql_real_escape_string () çıktısını nasıl ayrıştırdığına ilişkin bir hata tespit edildi. Sonuç olarak, karakter kümesine duyarlı işlev mysql_real_escape_string () kullanıldığında bile SQL enjeksiyonu mümkün olmuştur. Bu hata düzeltildi.

Çözümler. MySQL'i mysql_real_escape_string () ayrıştırmada hata için düzeltmeyi içeren bir sürüme yükseltemiyorsanız, ancak MySQL 5.0.1 veya üstünü çalıştırıyorsanız, geçici çözüm olarak NO_BACKSLASH_ESCAPES SQL modunu kullanabilirsiniz. (Bu mod MySQL 5.0.1'de sunulmuştur.) NO_BACKSLASH_ESCAPES, ters eğik çizginin özel bir karakter olarak görülmediği bir SQL standart uyumluluk modunu etkinleştirir. Sonuç, sorguların başarısız olacağı olacaktır.

Mevcut bağlantı için bu modu ayarlamak için aşağıdaki SQL ifadesini girin:

SET sql_mode='NO_BACKSLASH_ESCAPES';

Modu tüm istemciler için global olarak da ayarlayabilirsiniz:

SET GLOBAL sql_mode='NO_BACKSLASH_ESCAPES';

Bu SQL modu, sunucu başlatıldığında da otomatik olarak etkinleştirilebilir --sql-mode = NO_BACKSLASH_ESCAPES veya sunucu seçeneği dosyasında sql-mode = NO_BACKSLASH_ESCAPES (örneğin, my.cnf veya my.ini) sisteminize bağlı olarak). (Hata # 8378, CVE-2006-2753)

Ayrıca Hata # 8303'e bakın.


1
Bu uzun zaman önce düzeltildi.
Sağduyu

2
Ayrıca, NO_BACKSLASH_ESCAPES diğer güvenlik açıklarını ortaya çıkaran dikkat edin .
eggyal

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.