Альтернатива mysql_real_escape_string без подключения к БД

91

Я бы хотел, чтобы функция работала как mysql_real_escape_string без подключения к базе данных, так как иногда мне нужно проводить сухое тестирование без подключения к базе данных. mysql_escape_string устарел и поэтому нежелателен. Некоторые из моих выводов:

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

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

Вьетнам
источник
1
+1 Я сам пишу класс MySQL и использую mysql_real_escape_string () для привязки параметров. Я избегаю использования mysqli, поскольку не все хостинги его поддерживают. Я также избегаю многофайловых и многоклассовых библиотек. Что мне нужно, так это аккуратный и чистый одноклассник. Спасибо!
Viet
+1 мне тоже. Мой вариант использования - это SugarCRM APi, где мне нужно отправить фрагменты SQL в удаленный экземпляр SugarCRM через API. Каким бы неприятным это ни было, это то, с чем мне приходится работать (идите и трясите головы некоторых разработчиков SugarCRM). Мне нужно экранировать строки в SQL в приложении, которое использует API и полностью отделено от базы данных за экземпляром SugarCRM.
Джейсон

Ответы:

76

Невозможно безопасно избежать строки без подключения к БД. mysql_real_escape_string()и подготовленным операторам требуется соединение с базой данных, чтобы они могли экранировать строку, используя соответствующий набор символов - в противном случае атаки SQL-инъекций все еще возможны с использованием многобайтовых символов.

Если вы только тестируете , то вы также можете использовать mysql_escape_string(), это не на 100% гарантировано от атак SQL-инъекций, но невозможно построить что-то более безопасное без подключения к БД.

слишком много php
источник
1
+1 Спасибо за заметку. Я не очень уверен, как тестировать атаки SQL-инъекций с использованием многобайтовых символов.
Viet
2
Мне дали обновить старый код. Используется mysql_escape_stringбез подключения (все еще пытаюсь понять, почему). Поскольку эта функция устарела, мне просто интересно, как я могу ее заменить. Конечно, кажется разумным, что можно было бы указать «соответствующий набор символов» в любой функции, которая его заменяет, не открывая соединения.
JohnK
3
Невозможно? Что mysql_real_escape_string получает от соединения с базой данных, кроме данных конфигурации, которые можно передать вручную эквивалентной функции? Изменить: просто прочтите ниже, он вызывает библиотечную функцию в MySQL, поэтому есть некоторая обработка, которая происходит за пределами PHP. Он все еще может быть портативным, но поддерживать его в актуальном состоянии - это уже отдельный проект.
Джейсон
2
Что, если набор символов БД известен заранее?
jchook 09
7
Да, если вы знаете набор символов, что мешает выполнить экранирование без подключения?
Johan
67

Что ж, согласно справочной странице функции mysql_real_escape_string : «mysql_real_escape_string () вызывает библиотечную функцию MySQL mysql_real_escape_string, которая экранирует следующие символы: \ x00, \ n, \ r, \, ',« и \ x1a ».

Имея это в виду, функция, указанная во второй опубликованной вами ссылке, должна делать именно то, что вам нужно:

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

    return str_replace($search, $replace, $value);
}
зомбат
источник
6
Спасибо. Я бы предложил кое-что еще: функция escape ($ aQuery) {return strtr ($ aQuery, array ("\ x00" => '\ x00', "\ n" => '\ n', "\ r" => '\ r', '\\' => '\\\\', "'" => "\'", '"' => '\"', "\ x1a" => '\ x1a')) ; }
Viet
1
почему \ x1a заменяется на \\\ x1a, а не на \\ x1a? Это опечатка?
Michael Z
16
-1 Это крайне опасно. Если соединение с базой данных использует многобайтовый набор символов, такие простые побайтовые замены могут привести к повреждению данных (включая экранирование / кавычки символов) - это может быть намеренно использовано злоумышленником для внедрения произвольного SQL.
eggyal
Если вы неправильно укажете набор символов, это может быть опасно. Для многобайтовых наборов символов, если mysql использует это, кто-то может просто вставить байт, чтобы отменить \\. Многобайтовые наборы символов часто могут принимать что угодно в качестве второго байта, включая \\ для mysql, который не будет рассматривать его как отдельный \\, а как часть многобайтового символа. Понятия не имею, что происходит с UTF8. Я надеюсь, что с [0xB0, '\\'], что при попадании в недопустимый байт \\, который просто останавливается и запускается снова с этим байтом, а не проглатывает его.
jgmjgm
1
Если я знаю, что кодировка - utf8, безопасно ли использовать mb_strpos()mb_substr()создавать поведение, подобное substr_replace()) для этого?
SOFe
28

В отличие от моего другого ответа, эта следующая функция, вероятно, безопасна даже с многобайтовыми символами.

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

Я надеюсь, что кто-то более осведомленный, чем я, скажет мне, почему приведенный выше код не работает ...

слишком много php
источник
+1 Спасибо за дополнительные усилия. Я собираюсь узнать больше о многобайтовых SQL-инъекциях.
Viet
Я думаю, это должно быть $ return. = '\ X'. dechex ($ ord); вместо этого
Viet
1
Как правило, я предпочитаю использовать '\\' даже в строках, заключенных в одинарные кавычки, просто потому, что одиночный '\' может повлиять на следующий символ, если вы не будете осторожны. Я, наверное, снова просто ОКР.
too much php
1
Эта функция не следует правилам экранирования mysql и приведет к потере целостности данных. «MySQL распознает escape-последовательности, показанные в Таблице 9.1,« Управляющие последовательности специальных символов ». Для всех остальных escape-последовательностей обратная косая черта игнорируется. То есть экранированный символ интерпретируется так, как если бы он не был экранирован. Например,« \ x » просто «х». - dev.mysql.com/doc/refman/5.6/en/…
velcrow
2
Означает ли \ xAA что-то большее, чем текст «xAA» в строковом литерале MySQL? В документации, кажется, сказано, что \ x не имеет особого значения, поэтому \ будет проигнорирован. dev.mysql.com/doc/refman/5.0/en/string-literals.html
Джейсон
6

В результате дальнейших исследований я обнаружил:

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

Исправление безопасности:

При обработке многобайтового кодирования обнаружена дыра в безопасности SQL-инъекции. Ошибка была на сервере, некорректном анализе строки, экранированной с помощью функции C API mysql_real_escape_string ().

Эта уязвимость была обнаружена и сообщена Джошем Беркусом и Томом Лейном в рамках межпроектного сотрудничества консорциума OSDB в области безопасности. Дополнительные сведения о SQL-инъекции см. В следующем тексте.

Обсуждение. При обработке многобайтового кодирования обнаружена дыра в безопасности SQL-инъекций. Брешь в безопасности SQL-инъекции может включать ситуацию, при которой, когда пользователь предоставляет данные для вставки в базу данных, пользователь может вводить операторы SQL в данные, которые сервер будет выполнять. Что касается этой уязвимости, когда используется экранирование без учета набора символов (например, добавляетlashes () в PHP), можно обойти экранирование в некоторых многобайтовых наборах символов (например, SJIS, BIG5 и GBK). В результате такая функция, как addlashes (), не может предотвратить атаки с использованием SQL-инъекций. На стороне сервера исправить это невозможно. Лучшее решение для приложений - использовать экранирование с учетом набора символов, предлагаемое такой функцией, как mysql_real_escape_string ().

Однако была обнаружена ошибка в том, как сервер MySQL анализирует вывод mysql_real_escape_string (). В результате, даже когда использовалась функция mysql_real_escape_string (), поддерживающая набор символов, SQL-инъекция была возможна. Эта ошибка исправлена.

Обходные пути. Если вы не можете обновить MySQL до версии, которая включает исправление ошибки в синтаксическом анализе mysql_real_escape_string (), но запускаете MySQL 5.0.1 или выше, вы можете использовать режим SQL NO_BACKSLASH_ESCAPES в качестве обходного пути. (Этот режим был представлен в MySQL 5.0.1.) NO_BACKSLASH_ESCAPES включает стандартный режим совместимости SQL, в котором обратная косая черта не считается специальным символом. В результате запросы не будут выполнены.

Чтобы установить этот режим для текущего соединения, введите следующий оператор SQL:

SET sql_mode='NO_BACKSLASH_ESCAPES';

Вы также можете установить режим глобально для всех клиентов:

SET GLOBAL sql_mode='NO_BACKSLASH_ESCAPES';

Этот режим SQL также можно включить автоматически при запуске сервера с помощью параметра командной строки --sql-mode = NO_BACKSLASH_ESCAPES или путем установки sql-mode = NO_BACKSLASH_ESCAPES в файле параметров сервера (например, my.cnf или my.ini , в зависимости от вашей системы). (Ошибка № 8378, CVE-2006-2753).

См. Также Ошибка № 8303.

Вьетнам
источник
1
Это давно исправили.
Ваш здравый смысл
2
Также будьте осторожны, это NO_BACKSLASH_ESCAPES приводит к другим уязвимостям .
eggyal
2
Исправлено в 5.1.11 - Ссылка была битая, вот архив: web.archive.org/web/20120501203047/http://dev.mysql.com:80/doc/…
Bastion