У меня есть приложение, которое в значительной степени выиграет от использования динамических запросов mysql в сочетании с реальной escape-строкой mysql (mysqli). Если бы я запустил все данные, полученные от пользователя через реальный escape mysql, он был бы столь же безопасен, как и с помощью подготовленных инструкций mysql?
Являются ли динамические запросы mysql с sql-экранированием столь же безопасными, как и подготовленные операторы?
Ответ 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']}'";
?>
И когда я говорю "привыкнуть", я имею в виду, что я в конце концов сдался и только начал использовать подготовленные заявления!