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

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

3 ответа

Решение

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

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

Если бы я запускал все данные, полученные от пользователя, через MySQL, действительно ли это было бы безопасно, так же как с использованием подготовленных MySQL операторов?

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

Ладно, похоже, нужно еще раз объяснить, почему массовый выход из строя плох.

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

Правда в том:

  • Бегство не "дезинфицирует" ничего.
  • Побег не имеет ничего общего с уколами.
  • Экранирование не имеет ничего общего с пользовательским вводом.

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

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

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

НЕ поможет против инъекций.
Потому что экранирование - это просто средство форматирования строки, а не средство предотвращения инъекций.
Пойди разберись.

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

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

Чтобы быть в безопасности в этих обстоятельствах, см. Мой ответ, объясняющий инструкции ПОЛНОЙ защиты от инъекций SQL

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

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

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

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

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

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

Я думаю, что @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']}'";

?>

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

Другие вопросы по тегам