Являются ли динамические запросы mysql с sql-экранированием столь же безопасными, как и подготовленные операторы?

У меня есть приложение, которое в значительной степени выиграет от использования динамических запросов mysql в сочетании с реальной escape-строкой mysql (mysqli). Если бы я запустил все данные, полученные от пользователя через реальный escape mysql, он был бы столь же безопасен, как и с помощью подготовленных инструкций mysql?

Ответ 1

Определенно NO.

Хотя вопрос в заголовке неоднозначен и может быть интерпретирован как "Являются ли динамические запросы mysql с каждой его частью правильно отформатированы..." и, таким образом, имеют положительный ответ, вопрос в теле не

Если бы я запустил все данные, полученные от пользователя с помощью mysql real escape, он был бы столь же безопасным, как и с помощью подготовленных инструкций mysql?

Если вы посмотрите на этот вопрос ближе, вы поймете, что это всего лишь магические кавычки воплощения! Сама цель этой опозоренной, устаревшей и удаленной функции заключается в том, чтобы "запускать весь пользовательский ввод через escape".
Всем известно, что волшебные цитаты плохие. Почему положительный ответ?

Хорошо, кажется, что его нужно снова объяснить, почему массовое экранирование плохое.

Корень проблемы - довольно сильное заблуждение, которое разделяет почти каждый пользователь PHP:
У всех странная вера в то, что побег что-то делает на "опасных персонажах" (что они?) Делает их "безопасными" (как?). Излишне говорить, что это, но полный мусор.

Истина такова:

  • Эскапажи не "санируют" все.
  • Escaping не имеет ничего общего с инъекциями.
  • Escaping не имеет ничего общего с пользовательским вводом.

Escaping - это просто форматирование строки и ничего больше.
Когда вам это нужно - вам это нужно, несмотря на возможность инъекции.
Когда вам это не понадобится, это немного поможет.

Говоря о различиях с подготовленными операторами, существует хотя бы одна проблема (которая уже упоминалась много раз в теге sql-injection):
такой код

$clean = mysql_real_escape_string($_POST['some_dangerous_variable']);
$query = "SELECT * FROM someTable WHERE somevalue = $clean";

поможет вам НЕ против инъекции.
Beause escaping - это просто средство форматирования строк, а не превентор для инъекций любыми средствами.
Идите фигуру.

Однако у экранирования есть что-то общее с подготовленными утверждениями:
Они оба не гарантируют вас от инъекций, если

  • вы используете его только против пресловутого "пользовательского ввода", а не как строгое правило для построения ЛЮБОГО запроса, несмотря на источник данных.
  • если вам нужно вставить не данные, а идентификатор или ключевое слово.

Чтобы быть в безопасности в этих обстоятельствах, см. мой ответ, объясняющий ПОЛЬЗОВАТЕЛЬСКАЯ БЕЗОПАСНОСТЬ ПОЛЬЗОВАТЕЛЯ

Короче говоря: вы можете считать себя в безопасности, только если вы сделаете 2 существенных исправления и одно дополнение к вашему первоначальному утверждению:

Если я выполнил все данные , полученные от пользователя с помощью mysql real escape и всегда заключая его в кавычки (и, как упоминал ircmaxell, mysqli_set_charset() используется для создания mysqli_real_escape string() действительно работает (в редких случаях с использованием нечетной кодировки, такой как GBK)), будет ли она столь же безопасной, как и с использованием подготовленных инструкций mysql?

Следуя этим правилам - да, это было бы столь же безопасно, как и собственные подготовленные инструкции.

Ответ 2

Да, но квалифицированный да.

Вам нужно правильно избежать 100% ввода. И вам нужно правильно задать наборы символов (если вы используете C API, вам нужно вызвать mysql_set_character_set() вместо SET NAMES). Если вы пропустите одну крошечную вещь, вы уязвимы. Так что да, пока вы все делаете правильно...

И по этой причине многие люди будут рекомендовать подготовленные запросы. Не потому, что они более безопасны. Но поскольку они более прощающие...

Ответ 3

Я думаю, что @ircmaxell понял это.

В качестве продолжения, будьте в поиске такого рода вещей.
Я делал это все время:

<?php

//sanitize the dangerous posted variable...
$clean = mysql_real_escape_string($_POST['some_dangerous_variable']);

//...and then forget to use it!
$query = "SELECT * FROM someTable WHERE somevalue = '{$_POST['some_dangerous_variable']}'";

?>

И когда я говорю "привыкнуть", я имею в виду, что я в конце концов сдался и только начал использовать подготовленные заявления!