Недостатки mysql_real_escape_string?
Я видел, как несколько человек здесь утверждают, что объединение запросов с использованием mysql_real_escape_string
не защитит вас (полностью) от атак SQL-инъекций.
Тем не менее, мне еще предстоит увидеть пример ввода, который иллюстрирует атаку, которая mysql_real_escape_string
не защитит вас от Большинство примеров забывают, что mysql_query
ограничен одним запросом и использованием mysql_real_escape_string
неправильно.
Единственный пример, который я могу вспомнить, это следующее:
mysql_query('DELETE FROM users WHERE user_id = '.mysql_real_escape_string($input));
Это не защитит вас от следующего ввода:
5 OR 1=1
Я бы видел это как неправильное использование mysql_real_escape_string
скорее, чем недостаток, он предназначен для строк, а не числовых значений. Вам следует либо привести к числовому типу, либо, если вы собираетесь обрабатывать ввод как строку при очистке, вы должны сделать то же самое в своем запросе и заключить его в кавычки.
Может кто-нибудь привести пример ввода, который можно обойти mysql_real_escape_string
это не зависит от неправильной обработки числовых значений или забыть, что mysql_query
можно выполнить только один запрос?
Изменить: меня интересуют ограничения mysql_real_escape_string
и не сравнивая его с альтернативами, я понимаю, что есть лучшие варианты для новых проектов, и я не оспариваю это.
2 ответа
Главный недостаток mysql_real_escape_string
или расширения mysql_ в целом заключается в том, что его сложнее правильно применить, чем другие, более современные API, особенно подготовленные операторы. mysql_real_escape_string
предполагается использовать только в одном случае: экранирование текстового содержимого, которое используется в качестве значения в выражении SQL между кавычками. Например:
$value = mysql_real_escape_string($value, $link);
$sql = "... `foo` = '$value' ...";
^^^^^^
mysql_real_escape_string
удостоверяется, что $value
в приведенном выше контексте не портит синтаксис SQL. Это не работает, как вы можете подумать здесь:
$sql = "... `foo` = $value ...";
или здесь:
$sql = "... `$value` ...";
или здесь:
$sql = mysql_real_escape_string("... `foo` = '$value' ...");
При применении к значениям, которые используются в любом контексте, кроме строки в кавычках в операторе SQL, он применяется неправильно и может испортить или не испортить результирующий синтаксис и / или разрешить кому-либо передавать значения, которые могут включать атаки с использованием SQL-инъекций. Вариант использования mysql_real_escape_string
очень узкий, но редко правильно понимаемый.
Еще один способ получить себя в горячей воде, используя mysql_real_escape_string
это когда вы устанавливаете кодировку соединения с базой данных, используя неправильный метод. Вы должны сделать это:
mysql_set_charset('utf8', $link);
Вы также можете сделать это, хотя:
mysql_query("SET NAMES 'utf8'", $link);
Проблема в том, что последний обходит API mysql_, который все еще думает, что вы общаетесь с базой данных, используя latin1
(или что-то другое). Когда используешь mysql_real_escape_string
теперь он будет предполагать неправильную кодировку символов и escape-строки иначе, чем база данных будет интерпретировать их позже. Запустив SET NAMES
запрос, вы создали разрыв между тем, как mysql_ клиентский API обрабатывает строки и как база данных будет интерпретировать эти строки. Это может быть использовано для инъекционных атак в определенных многобайтовых строковых ситуациях.
Там нет фундаментальных уязвимостей инъекций в mysql_real_escape_string
что я знаю, если он применяется правильно. Опять же, однако, главная проблема заключается в том, что ужасно легко применять его неправильно, что открывает уязвимости.
Хорошо, кроме mysql_*
будучи осуждаемым, я понимаю, что вы хотите знать о любом возможном обходном пути, который может существовать. возможно, этот блог и слайды могут раскрыть некоторые из них.
Но, как показывает этот старый вопрос, приведение и цитирование не являются полным доказательством. Есть так много вещей, которые могут ошибаться, и закон Мерфи, увязанный с этой когда-либо действительной мантрой "Никогда не доверяй сети", будет ужасно неправильным.
Возможно, эта статья, но самое главное, продолжение этой статьи может выявить еще больше проблем безопасности. Если честно я знаю mysql_real_escape_string
не является полностью защищенным даже в сочетании с приведением типов и форматом строки:
printf('WHERE id = \'%d\'',(int)mysql_real_escape_string($_REQUEST['id']));
не охватывает все возможные атаки.
Я не эксперт в этом вопросе, но я могу сказать, что дезинфекция каждого ввода даст вам ЛОЖНОЕ чувство безопасности. Большую часть времени вы будете знать (изначально), что и почему и как вы защищаете от атак, но ваши коллеги могут этого не делать. Они могут что-то забыть, и вся ваша система будет взломана.
В итоге: Да, вы можете предотвратить попадание любых вредоносных данных в вашу БД, но каждое дополнительное действие, которое оно требует, представляет собой дополнительный риск. В этом сценарии наибольшая ответственность (как всегда) заключается в том, что разработчик не выпил четвертую чашку кофе в понедельник утром. Никакой код, каким бы защитным и продуманным он ни был, не сможет защитить себя от монстра, уставшего от дурного нрава разработчик, которому не хватает кофеина и никотина.