Необходимо избегать ввода пользователем из базы данных?

Итак, я знаю о введении 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 автоматически выходить из своего вывода или что-то в этом роде, или я должен избежать второго запроса?

Это тестовый файл, но это происходит в некоторых других способах моей программы, и мне интересно, насколько жесткой должна быть безопасность для таких случаев.

ИЗМЕНИТЬ

Моя функция escape

static function escape($string){

    if(get_magic_quotes_gpc()) 
        $string = stripslashes($string); 

    return mysql_real_escape_string($string);

}

Ответы

Ответ 1

Может ли MySQL автоматически выходить из своего вывода или что-то в этом роде, или я должен избежать второго запроса?

Вам также нужно скрыться во втором запросе. MySQL не выполняет никаких выходов на своем выходе.

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

Ответ 2

Да, вы также должны избегать строки во втором запросе.

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

Лучше всего было бы просто посмотреть, что происходит на самом деле. Скажем, что строка ввода:

'); 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);
}
Вторая причина, по которой это зло, состоит в том, что нет ничего общего с "универсальным цитированием" . При цитировании вы всегда цитируете текст для определенного выходного файла, например:
  • строковое значение для запроса mysql
  • like выражение для запроса mysql
  • html code
  • JSON
  • регулярное выражение mysql
  • регулярное выражение php

Для каждого случая вам нужно другое цитирование, потому что каждое использование присутствует в другом контексте синтаксиса. Это также подразумевает, что цитирование не должно производиться на входе в 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()

Ответ 3

Я бы сказал, что вся идея этого вопроса неверна.

Вы принимаете эту проблему абсолютно неправильно.
Не нужно рассчитывать на его запросы, если это первый или второй или 100-й.
То же самое касается ввода пользователя: это не имеет значения, откуда поступают данные!

Данные destination, а не источник. Эта строка идет в базу данных? Побег! Без вопросов. Это правило является простым и простым и не требует подсчета запросов или чего-либо еще.

Но это не только ошибка в вашем вопросе.
Один:

Может ли MySQL автоматически выйти из своего вывода или что-то в этом роде?

Это очень плохая идея. Смешная часть, вы сражаетесь с последствиями той же идеи в своем коде, применяя get_magic_quotes_gpc(). Каковы эти магические цитаты, если не такое автоматическое экранирование?

Два:
более того, использование get_magic_quotes_gpc() в вашей функции экранирования - это очень плохая идея:)

Представьте, что у вас есть волшебные кавычки и использование вашей функции для защиты вашего "второго запроса". И есть несколько blob, которые содержат \' последовательность в данных. Ваша функция отключит косую черту и испортит данные. Фактически, stripslashes абсолютно не имеет никакого отношения к любой функции экранирования. делайте это отдельно, по данным, где он принадлежит, - на входе пользователя.

Три
mysql_real_escape_string() не является некоторой магической функцией, которая "делает все в безопасности". Фактически, для создания динамического запроса mysql необходимо избегать четырех видов данных:

  • строки
  • числа
  • идентификаторы
  • Операторы

в то время как mysql_real_escape_string() удаляет только один из них. И ваш запрос абсолютно голый во всех трех других случаях. Забавно, а??

Самая разочаровывающая часть: Я знаю, что все эти конечные знания напрасны и вряд ли будут прочитаны немногими нубами и никогда не изменят ни общий уровень знаний сообщества PHP вообще, ни качество ответов на SO в частности.: (

Ответ 4

Попробуйте использовать PHP PDO для доступа к базе данных, если сможете. Для этого есть две важные причины:

  • Вы можете использовать функцию подготовки PDO для компиляции вашего запроса. Это эффективно, если вам нужно выдать один и тот же запрос с разными входами (как это часто бывает). Итак, скомпилируйте один раз и выполните несколько раз.
  • Компиляция запроса с подготовкой имеет другие приятные эффекты. После компиляции запроса механизм базы данных знает точную синтаксическую структуру запроса и не позволяет вводить какие-либо данные, которые изменяют эту синтаксическую структуру. Это хорошо, потому что в SQL-инъекции введенный ввод изменяет синтаксис запроса.

Предупреждение. Это не предотвращает все виды SQL-инъекций, но предотвращает наиболее распространенный вид.

Литература: