Поэтому я знаю о MySQL-инъекции и всегда избегаю ввода всех моих пользовательских данных перед тем, как поместить их в свою базу данных. Однако мне было интересно, представьте, что пользователь пытается отправить запрос для ввода, и я убегаю. Что делать, если я в последующий момент беру это значение из базы данных и использую его в запросе. Должен ли я снова избежать этого?
Итак: ( sql::escape()
содержит мою функцию escape)
$userinput = "'); DROP `table` --"; mysql_query("INSERT INTO `table` (`foo`,`bar`) VALUES ('foobar','".sql::escape($userinput)."')"); // insert php/mysql to fetch `table`.`bar` into $output here mysql_query("INSERT INTO `table2` (`foo`,`bar`) VALUES ('foobar','".$output."')");
Удаляет ли MySQL автоматически их выход или что-то в этом роде, или я должен убежать во втором запросе?
Это тестовый файл, но это происходит в некоторых других способах моей программы, и мне интересно, насколько жесткой должна быть безопасность для таких случаев.
РЕДАКТИРОВАТЬ
Моя функция выхода
static function escape($string){ if(get_magic_quotes_gpc()) $string = stripslashes($string); return mysql_real_escape_string($string); }
Удаляет ли MySQL автоматически их выход или что-то в этом роде, или я должен убежать во втором запросе?
Вам также нужно скрыться во втором запросе. MySQL не выполняет никаких выходов на выходе.
Длинный ответ: Сбой строки MySQL не изменяет введенную строку, он просто убеждается, что это не повредит текущему запросу . Любая попытка SQL-инъекции по-прежнему сохраняется в данных.
Сбежание струны звучит магически для многих людей, что-то вроде защиты от какой-то таинственной опасности, но на самом деле это не волшебство. Это просто способ включения специальных символов, обрабатываемых запросом.
Лучше всего было бы просто посмотреть, что происходит на самом деле. Скажем, строка ввода:
'); DROP `table` --
после побега:
\'); DROP `table` --
на самом деле он избежал единственной косой черты. Это единственное, что вам нужно заверить: когда вы вставляете строку в запрос, синтаксис будет ОК!
insert into table set column = '\'); DROP `table` --'
Это ничего волшебного, как защитный экран или что-то в этом роде, просто чтобы убедиться, что результирующий запрос имеет правильный синтаксис! (конечно, если это не так, его можно использовать)
Затем синтаксический анализатор запросов смотрит на последовательность и знает, что она по-прежнему является переменной, но не заканчивается ее значением. Он удалит обратную косую черту, и в базе данных будут сохранены следующие данные:
'); DROP `table` --
который точно такой же, как и введенный пользователем. И это именно то, что вы хотели иметь в базе данных!
Таким образом, это означает, что если вы извлекаете эту строку из базы данных и хотите снова использовать ее в запросе, вам нужно снова ее избежать, чтобы убедиться, что результирующий запрос имеет правильный синтаксис .
magic_quotes_gpc
! Эта функция автоматически пропускает все входные данные пользователя (gpc – _GET, _POST и _COOKIE). Это злая особенность, сделанная для людей, не знакомых с SQL-инъекцией. Это зло по двум причинам. Первая причина заключается в том, что тогда вам нужно различать случай первого и второго запросов – в первом случае вы не убегаете, а во втором вы делаете. То, что большинство людей делает, это либо отключить «функцию» (я предпочитаю это решение), либо сначала отключить ввод пользователя, а затем, при необходимости, сбежать от него. Код unescape может выглядеть так:
function stripslashes_deep($value) { return is_array($value) ? array_map('stripslashes_deep', $value) : stripslashes($value); } if (get_magic_quotes_gpc()) { $_POST = stripslashes_deep($_POST); $_GET = stripslashes_deep($_GET); $_COOKIE = stripslashes_deep($_COOKIE); }
Вторая причина, по которой это зло, состоит в том, что нет ничего подобного «универсальному цитированию» . При цитировании вы всегда цитируете текст для определенного вывода , например:
like
выражение для запроса mysql Для каждого случая вам нужно другое цитирование, потому что каждое использование присутствует в другом контексте синтаксиса. Это также подразумевает, что цитирование не должно производиться на входе в PHP, а на конкретном выходе ! Именно по этой причине функции, такие как magic_quotes_gpc
, сломаны ( никогда не забывайте обращаться с ним или, лучше, убедитесь, что он выключен !!! ).
Итак, какие методы можно использовать для цитирования в этих конкретных случаях? (Не стесняйтесь исправлять меня, могут быть более современные методы, но они работают для меня)
mysql_real_escape_string($str)
mysql_real_escape_string(addcslashes($str, "%_"))
htmlspecialchars($str)
json_encode()
– только для utf8! Я использую свою функцию для iso-8859-2 mysql_real_escape_string(addcslashes($str, '^.[]$()|*+?{}'))
– вы не можете использовать preg_quote в этом случае, потому что обратная косая черта будет сбрасываться два раза! preg_quote()
Я бы сказал, что вся идея этого вопроса неверна.
Вы принимаете эту проблему совершенно неправильно.
Не нужно рассчитывать на его запросы, если это первый или второй или 100-й.
То же самое касается ввода пользователя: это не имеет значения, откуда берутся данные!
Назначение данных, а не источник, должно быть вашей проблемой. Эта строка идет в базу данных? Побег! Без вопросов. Это правило является простым и простым и не требует подсчета запросов или чего-либо еще.
Но это не только вина в вашем вопросе.
Один:
Удаляет ли MySQL автоматически их выход или что-то в этом роде?
Это очень плохая идея. Смешная часть, вы сражаетесь с последствиями той же идеи в своем коде, применяя get_magic_quotes_gpc (). Каковы эти магические цитаты, если не такое автоматическое экранирование?
Два:
более того, использование get_magic_quotes_gpc () в вашей функции экранирования – очень плохая идея снова 🙂
представьте, что у вас есть магические кавычки и использование вашей функции для защиты вашего «второго запроса». И есть некоторые blob, которые содержат последовательность в данных. Ваша функция отключит косую черту и испортит данные. Фактически, stripslashes абсолютно не имеет никакого отношения к любой функции экранирования. делайте это отдельно, по данным, где он принадлежит, – на входе пользователя.
Три:
mysql_real_escape_string () не является некоторой магической функцией, которая «делает все в безопасности». Фактически, для создания динамического запроса mysql необходимо избегать четырех видов данных:
в то время как mysql_real_escape_string () избегает только одного из них. И ваш запрос абсолютно голый во всех трех других случаях. Забавно, а?
Самая разочаровывающая часть: я знаю, что все эти конечные знания напрасны и вряд ли будут прочитаны немногими нубами и никогда не изменят ни общий уровень знаний сообщества PHP вообще, ни качество ответов на SO в частности. 🙁
Попытайтесь использовать PDO PHP для доступа к базе данных, если сможете. Для этого есть две важные причины:
Предупреждение. Это не предотвращает все виды SQL-инъекций, но это предотвращает наиболее распространенный вид.
Рекомендации: