Альтернатива 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, оскільки не всі хостинги його підтримують. Я також уникаю багатофайлової та багатокласної бібліотеки. Мені потрібен просто акуратний та чистий єдиний клас. Дякую!
В'єт

+1 для мене теж. Моїм варіантом використання є APi SugarCRM, де мені потрібно надсилати фрагменти SQL до віддаленого екземпляра SugarCRM через API. Хоч це неприємно, це те, з чим мені доводиться працювати (сходи, збивай разом кілька головок розробників SugarCRM). Мені потрібно уникати рядків у SQL у програмі, яка використовує API, і яка повністю відокремлена від бази даних за екземпляром SugarCRM.
Джейсон

Відповіді:


75

Неможливо безпечно уникнути рядка без підключення до БД. mysql_real_escape_string()і підготовленим операторам потрібне з'єднання з базою даних, щоб вони могли уникнути рядка, використовуючи відповідний набір символів - інакше атаки введення SQL все ще можливі за допомогою багатобайтових символів.

Якщо ви лише тестуєте , тоді ви можете також використовувати mysql_escape_string(), це не на 100% гарантоване проти атак SQL-ін'єкції, але неможливо створити щось безпечніше без з'єднання з БД.


1
+1 Дякую за примітку. Я не дуже впевнений, як протестувати проти атак SQL-ін'єкцій за допомогою багатобайтових символів.
В'єтнам,

2
Мені дали старий код для оновлення. Він використовує mysql_escape_stringбез підключення (все ще намагається зрозуміти, чому). Оскільки ця функція застаріла, мені просто цікаво, як я можу її замінити. Безумовно, здається розумним, що можна вказати "відповідний набір символів" у будь-якій функції, яка його замінює, не розмикаючи з'єднання.
JohnK

3
Неможливо? Що отримує mysql_real_escape_string від підключення до бази даних, що не є даними конфігурації, які можна вручну передавати еквівалентній функції? Редагувати: просто прочитайте нижче, він викликає функцію бібліотеки в MySQL, тому є деяка обробка, яка відбувається поза PHP. Він все ще може бути портативним, але його оновлення буде проектом сам по собі.
Джейсон

2
Що робити, якщо набір символів БД відомий заздалегідь?
jchook

7
Так, якщо ви знаєте набір символів, що заважає виконувати втечу без зв’язку?
Йохан

66

Ну, відповідно до довідкової сторінки функції 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')) ; }
В'єтнам

1
чому \ x1a замінюється на \\\ x1a, а не \\ x1a? Це друкарська помилка?
Michael Z

16
-1 Це надзвичайно небезпечно. Якщо підключення до бази даних використовує багатобайтовий набір символів, прості побітові заміни, подібні до цього, можуть призвести до пошкодження даних (у тому числі до символів, що виходять з екрана / цитування) - це може бути навмисно використано зловмисником для введення довільного SQL.
eggyal

Якщо ви неправильно розберете набори символів, це може бути небезпечно. Для багатобайтових наборів символів, якщо mysql використовує, хтось може просто ввести байт, щоб скасувати \\. Багатобайтові набори символів часто можуть приймати все, що завгодно, оскільки другий байт, включаючи \\ для mysql, не бачить його як самостійний \\, але є частиною багатобайтового символу. Я не уявляю, що відбувається з UTF8. Я сподівався б, що з [0xB0, '\\'] це при попаданні на невірний байт \\, який просто зупиняється і починається знову з цього байта, а не проковтує його.
jgmjgm

1
Якщо я знаю, що набір символів - utf8, чи безпечно використовувати mb_strpos()mb_substr()створювати подібну поведінку substr_replace()) для цього?
SOF,

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

Я сподіваюся, що хтось більш обізнаний, ніж я, може сказати мені, чому код вище не працюватиме ...


+1 Дякую за додаткові зусилля. Я збираюся дізнатись більше про багатобайтові SQL-ін’єкції, пов’язані з ними.
В'єт,

Думаю, це має бути $ return. = '\ X'. дехекс ($ ордер); натомість
В'єт

1
Як загальне правило, я вважаю за краще використовувати '\\' навіть у рядках з одинарними лапками, просто тому, що одиничне '\' може впливати на наступний символ, якщо ви не будете обережні. Я, мабуть, просто знову страждаю на ОКР.
занадто багато php

1
Ця функція не відповідає правилам екранування mysql і призведе до втрати цілісності даних. "MySQL розпізнає екрануючі послідовності, показані в таблиці 9.1," Спеціальні послідовності втечі символів ". Для всіх інших послідовностей екранування зворотна коса риса ігнорується. Тобто, екранований символ інтерпретується так, ніби він не був захищений. Наприклад," \ 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. Помилка була на сервері, неправильно проаналізований рядок, який уникнув за допомогою функції API API mysql_real_escape_string ().

Цю вразливість виявили і повідомили Джош Беркус і Том Лейн в рамках співпраці між проектами в галузі безпеки консорціуму OSDB. Для отримання додаткової інформації про введення SQL див. Наступний текст.

Обговорення. У багатобайтовій обробці кодування виявлено дірку безпеки введення SQL. Дірка безпеки введення SQL може включати ситуацію, коли, коли користувач надає дані, які потрібно вставити в базу даних, користувач може вводити оператори SQL у дані, які виконуватиме сервер. Що стосується цієї вразливості, то, коли використовується екранування невідомого набору символів (наприклад, додавання косих знаків () у 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/…
Бастіон
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.