Является ли mysql_real_escape_string уязвимым для недействительной работы UTF-8, например, чередующихся UTF-8 или плохо сформированных последовательностей UTF-8?

Предполагая, что моя база данных настроена следующим образом, чтобы использовать utf-8 (полная версия 4mb в mysql)

mysql_query("SET CHARACTER SET utf8mb4");
mysql_query("SET NAMES utf8mb4");

Я использую mysql_real_escape_string для удаления нежелательных символов перед тем, как поместить строку в sql (примечание - я не ищу совета для переключения на PDO, я хочу установить, является ли mysql_real_escape_string безопасным с помощью overlong utf8 и т.д.).

$input = mysql_real_escape_string($_POST['field']);
$sql = "SELECT * FROM `table` WHERE `header`='$input'";

Есть ли какая-либо проверка, которую мне нужно сделать для $_POST ['field'] (например, чтобы проверить правильность строки UTF-8 и не перекрывается и не содержит недопустимых последовательностей и т.д.), прежде чем делать mysql_real_escape_string или это достаточно?

Ответ 1

Все проверки ввода и анти-SQL-инъекция подвержены многим ошибочным представлениям. Фактически, все это сводится к одной единственной вещи:

Обеспечить правильный синтаксис SQL-запроса

Если вы можете обеспечить правильный синтаксис SQL для любых входных данных, вы в безопасности, и вам не нужно вообще ничего читать или изучать что-либо о валидации или SQL-инъекции. Поскольку все эти уязвимости возможны только в ситуациях, когда вы допускаете неправильный синтаксис SQL.

Чтобы обеспечить правильный синтаксис SQL-запроса в вашем случае, вы должны убедиться, что ваш $input экранирован правильно. Посмотрите на документы PHP: http://php.net/mysql_real_escape_string:

Предупреждение Безопасность: набор символов по умолчанию

Набор символов должен быть установлен либо на уровне сервера, либо с помощью Функция API mysql_set_charset(), чтобы она влияла mysql_real_escape_string(). См. Раздел "Концепции" на наборах символов для получения дополнительной информации.

Итак, mysql_real_escape_string должен быть правильно проинформирован о вашем наборе символов, чтобы быть в состоянии убежать должным образом. Итак, вместо вашего mysql_query("SET NAMES utf8mb4"); вы должны сделать:

mysql_set_charset("utf8mb4");

Ответ 2

Объявление публичной службы перед моим ответом. Вы по-прежнему используете mysql_query. Вам, в конце концов, придется обновиться до mysqli, по крайней мере, даже если вы не хотите идти PDO. Все функции mysql_ обесцениваются (см. Большое красное страшное поле в предыдущей ссылке) и, вероятно, будут удалены в PHP 5.6. Это важно, потому что основная причина предложить PDO в вашем случае подготовленные инструкции, которые также могут выполнять mysqli. Подготовленный оператор гораздо менее уязвим для инъекций, чем ускользает, но требует большего количества запросов (малой производительности).

Что касается UTF8, то я бы рекомендовал использовать mb_check_encoding, чтобы убедиться, что строка является, по крайней мере, допустимой UTF8, прежде чем пытаться ее вставить.

Наконец, там этот ответ, который предлагает эти слова мудрости

Еще один способ попасть в горячую воду, используя 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, вы создали разрыв между тем, как обрабатывается API-интерфейс mysql_ строки и то, как база данных будет интерпретировать эти строки. Это может быть используется для инъекционных атак в определенных многобайтовых строковых ситуациях.