Нужен ли выход пользователя из базы данных? - PullRequest
15 голосов
/ 16 сентября 2011

Итак, я знаю о внедрении 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);

}

Ответы [ 4 ]

14 голосов
/ 16 сентября 2011

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

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

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

5 голосов
/ 23 сентября 2011

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

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

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

'); 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);
}

Вторая причина, почему это зло, заключается в том, что нет ничего похожего на "универсальное цитирование" .При цитировании вы всегда цитируете текст для определенного вывода , например:

  1. строковое значение для запроса mysql
  2. like выражениедля запроса MySQL
  3. HTML-код
  4. JSON
  5. MySQL регулярное выражение
  6. PHP регулярное выражение

Для каждого случая вынужно различное цитирование, потому что каждое использование присутствует в различном синтаксическом контексте.Это также подразумевает, что цитирование должно производиться не при вводе в PHP, а при конкретном выводе !По этой причине такие функции, как magic_quotes_gpc, не работают ( никогда не забывайте обращаться с ним, или, что еще лучше, убедитесь, что он выключен !!! ).

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

  1. mysql_real_escape_string($str)
  2. mysql_real_escape_string(addcslashes($str, "%_"))
  3. htmlspecialchars($str)
  4. json_encode() - только для utf8!Я использую свою функцию для iso-8859-2
  5. mysql_real_escape_string(addcslashes($str, '^.[]$()|*+?{}')) - вы не можете использовать preg_quote в этом случае, потому что обратный слэш будет экранирован два раза!
  6. preg_quote()
4 голосов
/ 23 сентября 2011

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

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

Данные Назначение , а не источник должен быть вашей заботой.Эта строка собирается в базу данных?Побег это!Без вопросов.Это правило простое и не требует подсчета запросов или чего-либо еще.

Но это не единственная ошибка в вашем вопросе.
One:

MySQL автоматически экранирует свой вывод или что-то в этом роде?

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

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

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

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

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

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

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

2 голосов
/ 16 сентября 2011

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

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

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

Ссылки:

  1. Достаточно ли подготовленных операторов PDO для предотвращения внедрения SQL?
  2. http://php.net/manual/en/pdo.prepare.php
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...