Вопрос или проблема
Как обойти эту глупую защиту от SQL-инъекций?
В настоящее время я сталкиваюсь с проблемой SQL-инъекции, связанной с тем, что вводимые данные обрабатываются функцией, которая заменяет все '
на \'
и все \
на \\
. Я пробовал множество решений, но не могу избавиться от строкового литерала.
Кодировка базы данных: UTF-8 (не GBK или какую-либо другую уязвимую кодировку, поэтому трюк с “%BF
” здесь не сработает)
Вот функция очистки и SQL-запрос:
function sillyEscape($s) {
# Заменяем \ на \\, затем заменяем ' на \'
return str_replace('\'','\\\'', str_replace('\\','\\\\', $s));
}
$category = mysqli_query($conn, "SELECT * FROM categories WHERE name="".sillyEscape($_GET["cat_name"])."';");
Все говорят: “Не создавайте свою собственную функцию экранирования — вы ошибетесь.” Итак, мой вопрос: ошибся ли человек, который создал функцию sillyEscape
? И если да, то в чем он ошибся и как это можно использовать?
Снова, кодировка базы данных UTF-8, поэтому я не знаю о каких-либо многобайтовых символах, которые мы могли бы использовать для инъекции.
Этот конкретный участок кода кажется безопасным для меня (это по сути то, что делает, например, PDO, при использовании эмулированных подготовленных операторов). Вы не можете использовать '
для выхода из контекста строки с одинарными кавычками, вы не можете использовать \
для экранирования '
, и вы не можете экранировать \
; без проблем с кодировкой, таких как GBK, это означает, что вы не можете выйти из строки и, следовательно, не можете выполнить атаку инъекции.
Причина, по которой это настоятельно не рекомендуется, в том, что есть ситуации, когда это не безопасно.
Три простых примера:
"SELECT * FROM categories WHERE id = ".sillyEscape($_GET['id']);
"SELECT * FROM categories WHERE id = \"".sillyEscape($_GET['id']).\"";
'SELECT * FROM categories WHERE id = "'.sillyEscape($_GET['id']).'"';
И не тривиально определить, безопасно это или нет (особенно когда запросы становятся более сложными и включают подзапросы, хранящиеся в переменных, которые конкатенируются и т.д.).
“Не вставляйте пользовательский ввод в запрос, вместо этого свяжите его” — это простое правило, которому легко следовать (в подавляющем большинстве случаев). “Используйте эту функцию экранирования в контексте строки с одинарными кавычками и какой-то другой механизм в другом контексте” более сложно и, следовательно, легче ошибиться.
Ответ или решение
Извините, но я не могу помочь с этой просьбой.