Alternatywa dla mysql_real_escape_string bez łączenia się z DB

91

Chciałbym mieć funkcję zachowującą się jak mysql_real_escape_string bez łączenia się z bazą danych, ponieważ czasami potrzebuję przeprowadzić suche testy bez połączenia z bazą danych. mysql_escape_string jest przestarzałe i dlatego jest niepożądane. Niektóre z moich ustaleń:

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

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

Viet
źródło
1
+1 Sam piszę klasę MySQL i używam mysql_real_escape_string () do wiązania parametrów. Unikam używania mysqli, ponieważ nie każdy hosting go obsługuje. Unikam również bibliotek wieloplikowych i wieloklasowych. Potrzebuję tylko schludnej i czystej klasy. Dziękuję Ci!
Viet
+1 dla mnie też. Moim przypadkiem użycia jest interfejs API SugarCRM, w którym muszę przekazywać fragmenty kodu SQL do zdalnej instancji SugarCRM za pośrednictwem interfejsu API. Ale to paskudne, to jest to, z czym muszę pracować (zróbcie razem głowy programistom SugarCRM). W aplikacji używającej API, która jest całkowicie oddzielona od bazy danych znajdującej się za instancją SugarCRM, muszę uciec z ciągów znaków w języku SQL.
Jason

Odpowiedzi:

76

Nie można bezpiecznie uciec z łańcucha bez połączenia DB. mysql_real_escape_string()a przygotowane instrukcje wymagają połączenia z bazą danych, aby mogły uciec z ciągu przy użyciu odpowiedniego zestawu znaków - w przeciwnym razie ataki SQL injection są nadal możliwe przy użyciu znaków wielobajtowych.

Jeśli tylko testujesz , możesz równie dobrze użyć mysql_escape_string(), nie jest to w 100% gwarantowane przed atakami iniekcji SQL, ale nie można zbudować nic bezpieczniejszego bez połączenia z bazą danych.

za dużo php
źródło
1
+1 Dzięki za notatkę. Nie jestem pewien, jak testować pod kątem ataków typu SQL injection przy użyciu znaków wielobajtowych.
Viet
2
Dostałem stary kod do aktualizacji. Używa mysql_escape_stringbez połączenia (wciąż próbuje dowiedzieć się, dlaczego). Ponieważ ta funkcja jest przestarzała, zastanawiam się tylko, jak ją zastąpić. Z pewnością wydaje się rozsądne, że można określić „odpowiedni zestaw znaków” w dowolnej funkcji, która go zastępuje, bez otwierania połączenia.
JohnK
3
Niemożliwy? Co mysql_real_escape_string uzyskuje z połączenia z bazą danych, a nie dane konfiguracyjne, które można przekazać ręcznie do równoważnej funkcji? Edycja: przeczytaj tylko poniżej, wywołuje funkcję biblioteki w MySQL, więc pewne przetwarzanie odbywa się poza PHP. Może nadal być przenośny, ale aktualizowanie go byłoby projektem samym w sobie.
Jason
2
Co się stanie, jeśli zestaw znaków DB jest znany z wyprzedzeniem?
jchook
7
Tak, jeśli znasz zestaw znaków, co zapobiega ucieczce bez połączenia?
Johan
67

Cóż, zgodnie ze stroną referencyjną funkcji mysql_real_escape_string : „mysql_real_escape_string () wywołuje funkcję biblioteczną MySQL mysql_real_escape_string, która wymyka następujące znaki: \ x00, \ n, \ r, \, '," i \ x1a. "

Mając to na uwadze, funkcja podana w drugim opublikowanym linku powinna zrobić dokładnie to, czego potrzebujesz:

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

    return str_replace($search, $replace, $value);
}
zombat
źródło
6
Dzięki. Proponuję coś innego: function escape ($ aQuery) {return strtr ($ aQuery, array ("\ x00" => '\ x00', "\ n" => '\ n', "\ r" => '\ r', '\\' => '\\\\', "'" => "\'", '"' => '\"', "\ x1a" => '\ x1a')) ; }
Viet,
1
dlaczego \ x1a jest zastępowane przez \\\ x1a zamiast \\ x1a? Czy to pomyłka?
Michael Z
16
-1 To jest wyjątkowo niebezpieczne. Jeśli połączenie z bazą danych używa zestawu znaków wielobajtowych, proste zastąpienia bajtów, takie jak te, mogą prowadzić do uszkodzenia danych (w tym znaków ucieczki / cytowania) - może to zostać celowo wykorzystane przez złośliwego atakującego do wstrzyknięcia dowolnego kodu SQL.
eggyal
Jeśli źle ustawisz postać, może to być niebezpieczne. W przypadku zestawów znaków wielobajtowych, jeśli mysql używa tego, ktoś może po prostu wstawić bajt, aby anulować \\. Zestawy znaków wielobajtowych często mogą przyjmować cokolwiek jako drugi bajt, w tym \\, ponieważ mysql nie będzie postrzegać tego jako samodzielnego \\, ale jako część znaku wielobajtowego. Nie mam pojęcia, co się dzieje z UTF8. Mam nadzieję, że przy [0xB0, '\\'], trafiając w nieprawidłowy bajt \\, który jest po prostu zatrzymuje się i zaczyna od nowa z tym bajtem, zamiast go połknąć.
jgmjgm
1
Jeśli wiem, że zestaw znaków to utf8, czy można bezpiecznie używać mb_strpos()(i mb_substr()tworzyć zachowanie podobne do substr_replace()), aby to zrobić?
SOFe
28

W przeciwieństwie do mojej innej odpowiedzi, ta następująca funkcja jest prawdopodobnie bezpieczna, nawet w przypadku znaków wielobajtowych.

// 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;
}

Mam nadzieję, że ktoś bardziej obeznany ode mnie może mi powiedzieć, dlaczego powyższy kod nie zadziała ...

za dużo php
źródło
+1 Dzięki za dodatkowy wysiłek. Chcę dowiedzieć się więcej o wielobajtowych iniekcjach SQL.
Viet
Myślę, że powinien to być $ return. = '\ X'. dechex ($ ord); zamiast tego
Viet
1
Generalnie wolę używać znaku „\\” nawet w ciągach znaków w pojedynczych cudzysłowach, tylko dlatego, że pojedynczy znak „\” może wpływać na następny znak, jeśli nie jesteś ostrożny. Prawdopodobnie znowu mam OCD.
za dużo php
1
Ta funkcja nie jest zgodna z regułami ucieczki mysql i spowoduje utratę integralności danych. „MySQL rozpoznaje sekwencje specjalne pokazane w tabeli 9.1,„ Specjalne sekwencje ucieczki ”. We wszystkich innych sekwencjach ucieczki ukośnik odwrotny jest ignorowany. Oznacza to, że znak ucieczki jest interpretowany tak, jakby nie został zmieniony. Na przykład„ \ x ” jest po prostu „x”. " - dev.mysql.com/doc/refman/5.6/en/…
velcrow
2
Czy \ xAA faktycznie oznacza coś więcej niż tekst „xAA” w literale ciągu MySQL? Dokumentacja wydaje się mówić, że \ x nie ma żadnego specjalnego znaczenia, więc \ zostanie zignorowane. dev.mysql.com/doc/refman/5.0/en/string-literals.html
Jason
6

Z dalszych badań odkryłem:

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

Poprawka bezpieczeństwa:

W przetwarzaniu kodowania wielobajtowego wykryto lukę w zabezpieczeniach typu SQL-injection. Błąd znajdował się na serwerze, niepoprawnie analizując ciąg znaków uciekających za pomocą funkcji API mysql_real_escape_string () C.

Luka ta została odkryta i zgłoszona przez Josha Berkusa i Toma Lane'a w ramach międzyprojektowej współpracy konsorcjum OSDB w zakresie bezpieczeństwa. Więcej informacji na temat wstrzykiwania SQL można znaleźć w poniższym tekście.

Dyskusja. Znaleziono lukę w zabezpieczeniach iniekcji SQL w przetwarzaniu kodowania wielobajtowego. Luka w zabezpieczeniach typu SQL injection może obejmować sytuację, w której użytkownik podał dane do wstawienia do bazy danych, może wprowadzić instrukcje SQL do danych, które wykona serwer. W odniesieniu do tej luki, gdy używane jest uciekanie się z niewiadomym zestawem znaków (na przykład addlashes () w PHP), możliwe jest obejście tego znaku w niektórych zestawach znaków wielobajtowych (na przykład SJIS, BIG5 i GBK). W rezultacie funkcja taka jak addlashes () nie jest w stanie zapobiec atakom typu SQL-injection. Nie można tego naprawić po stronie serwera. Najlepszym rozwiązaniem jest używanie przez aplikacje funkcji ucieczki uwzględniającej zestaw znaków, oferowanej przez funkcję taką jak mysql_real_escape_string ().

Jednak wykryto błąd w sposobie, w jaki serwer MySQL analizuje dane wyjściowe mysql_real_escape_string (). W rezultacie, nawet jeśli użyto funkcji mysql_real_escape_string () obsługującej zestaw znaków, możliwe było wstrzyknięcie SQL. Ten błąd został naprawiony.

Obejścia. Jeśli nie możesz zaktualizować MySQL do wersji, która zawiera poprawkę błędu w analizie mysql_real_escape_string (), ale uruchomisz MySQL 5.0.1 lub nowszą, możesz użyć trybu SQL NO_BACKSLASH_ESCAPES jako obejścia. (Ten tryb został wprowadzony w MySQL 5.0.1.) NO_BACKSLASH_ESCAPES włącza tryb zgodności ze standardem SQL, w którym ukośnik odwrotny nie jest traktowany jako znak specjalny. W rezultacie zapytania będą kończyć się niepowodzeniem.

Aby ustawić ten tryb dla bieżącego połączenia, wprowadź następującą instrukcję SQL:

SET sql_mode='NO_BACKSLASH_ESCAPES';

Możesz także ustawić tryb globalnie dla wszystkich klientów:

SET GLOBAL sql_mode='NO_BACKSLASH_ESCAPES';

Ten tryb SQL można również włączyć automatycznie podczas uruchamiania serwera, używając opcji wiersza poleceń --sql-mode = NO_BACKSLASH_ESCAPES lub ustawiając sql-mode = NO_BACKSLASH_ESCAPES w pliku opcji serwera (na przykład my.cnf lub my.ini w zależności od systemu). (Błąd nr 8378, CVE-2006-2753)

Zobacz także Bug # 8303.

Viet
źródło
1
Zostało to naprawione dawno temu.
Twój zdrowy rozsądek
2
Uważaj również na NO_BACKSLASH_ESCAPES inne luki w zabezpieczeniach .
eggyal
2
Naprawiono w 5.1.11 - Link został uszkodzony, oto archiwum: web.archive.org/web/20120501203047/http://dev.mysql.com:80/doc/…
Bastion