Никто не ответил на ваш вопрос правильно, поэтому я сделаю удар по нему.
->where('u.name LIKE ?', array("%$name%"));
->where('u.username LIKE ?', '%'.$username.'%')
Ни один из них не является безопасным.Позвольте мне объяснить несколько сценариев.
Сценарий 1
Представьте, что вы хотите, чтобы пользователи могли искать подходящие имена пользователей, но никогда не хотите перечислять ВСЕ имена пользователей.Возможно, вы не хотите, чтобы кто-то легко украл у вас список из миллиона имен пользователей.где-то до этого кода вы сделали что-то вроде этого:
if (strlen(trim($name)) < 5) throw Boogey_Monster_Exception();
Вы думали, что это не позволит кому-либо оставить поле пустым и вытащить список всех имен пользователей ... но на самом деле пользователь может отправить«_____» или «%%%%%» или что-либо подобное, чтобы получить список всех имен пользователей, а не просто совпадение с 5 или более известными символами.
Я лично видел эту форму атаки, использовавшуюся для нескольких крупных,общедоступные веб-сайты.
Сценарий 2
У вас есть веб-сайт с большим количеством пользователей и большим количеством пользовательских данных.У вас есть 10 000 000 строк в вашей пользовательской таблице.Вы хотите, чтобы пользователи сайта могли найти имя пользователя другого пользователя, выполнив поиск известных префиксов.
Таким образом, вы пишете некоторый код, подобный этому, слегка измененный из приведенного выше примера, чтобы иметь только подстановочный знак ПОСЛЕ строки поиска.
->where('u.name LIKE ?', array("$name%"));
Если у вас есть индекс для u.name, тогда этот запрос LIKE будет использовать индекс.Поэтому, если пользователь отправляет $ name = "john", тогда этот запрос будет эффективно сопоставлять пользователей, таких как johndoe, johnwayne, johnwaynegacy и т. Д.
Однако, если пользователь отправляет $ name = "% john" вместо этого, этоЗапрос больше не использует индекс и теперь требует полного сканирования таблицы.В очень большой базе данных это может быть очень медленный запрос.
В руководстве MySQL по SQLi упоминается то же самое (стр. 78-79), и я нашел несколько примеров медленной производительности запроса и нашел одну ссылку.
Это может показаться не таким уж большим делом, но для сайтов, поддерживаемых RDBMS, RDBMS, как правило, является существенным узким местом, и большая часть проектирования производительности связана с уменьшением конкуренции за RDBMS.Если у вас есть несколько пользователей, запускающих атаку, которая связывает дескриптор базы данных на 60+ секунд, и у вас есть небольшой пул дескрипторов базы данных, вы можете увидеть, как это может быстро масштабироваться для монополизации всех дескрипторов базы данных и предотвращения легитимных пользователей.от возможности получить его.
Ссылки
http://dev.mysql.com/tech-resources/articles/guide-to-php-security-ch3.pdf
http://forums.mysql.com/read.php?24,13397,13397
Решение
В любом случае, лучшее решение (как упомянуто в руководстве MySQL, связанном выше и комментатором @Maxence, заключается в использовании addcslashes ()):
$username = addcslashes("%something_", "%_");
Обратите внимание, что, поскольку примеры sqlздесь используются подготовленные операторы, которые полностью невосприимчивы к SQL-инъекции; нет необходимости или нежелательно использовать mysql_real_escape_string ();побег, который он выполняет, предназначен исключительно для предотвращения внедрения SQL.То, что мы пытаемся предотвратить, - это использование подстановочных знаков, для чего требуется функция, которая экранирует два подстановочных знака sql, «%» и «_».