Кавычки в SQL - PullRequest
       70

Кавычки в SQL

7 голосов
/ 01 февраля 2011

Я немного запутался в этой теме, поэтому я решил спросить об этом у вас, ребята:)

Начиная с php.net я должен использовать mysql_real_escape_string () и отключить магические кавычки , потому что он устарел.

Итак, я выключил и использую mysql_real_escape_string (), но достаточно ли использовать его так же, как это?

$value = "It's Time!";
$escaped_value = mysql_real_escape_string($value);

mysql_query("INSERT INTO table (column, column2) VALUES ('{$escaped_value}', "0")");

Когда я проверяю данные в базе данных, они выглядят так же, как в $ value, поэтому "It's Time", а не "It\'s Time", разве это нормально, разве это не должно добавлять косую черту перед кавычками?

Ответы [ 3 ]

10 голосов
/ 01 февраля 2011

Краткий ответ

Это правильно.

Длинный ответ

Это правильно, но ваш вопрос указывает на недостаточное понимание того, что здесь происходит. Вот ваш запрос:

INSERT INTO table (column, column2) VALUES ('{$escaped_value}', "0")

Посмотрим, что произойдет, если вы не уйдете, и пользователь введет следующие данные:

Eve'

Помните, что вы просто передаете строку в MySQL, вставка выполняется обработкой строк в PHP. Это означает, что в данном случае запрос, отправляемый mysql_query:

INSERT INTO table (column, column2) VALUES ('Eve'', "0")

Что является синтаксической ошибкой и может привести к ошибке страницы. Теперь, когда такой пользователь, как я (т. Е. Ублюдок, намеревающийся сделать ваш день несчастным: D), замечает одного из них, мы знаем, что пришло время играть. Что произойдет, если пользователь предоставит следующие данные?

Eve', "0"); DROP TABLE table--

Наш запрос расширен до:

INSERT INTO table (column, column2) VALUES ('Eve', "0"); DROP TABLE table--', "0")

Это не синтаксическая ошибка, но она проблематична ... сейчас мы выполняем запрос, на который мы никогда не собирались! (Если вы его не распознаете, «-» обозначает комментарий в SQL, т. Е. «Игнорируйте все после этой точки»).

Теперь это не может произойти в данном конкретном случае ( mysql_query не поддерживает множественные запросы ), но это та атака, которую вы пытаетесь предотвратить - класс атак, известный как SQL-инъекция . Давайте посмотрим, что произойдет, когда вы используете mysql_real_escape_string!

Введенные данные становятся:

Eve\', \"0\"); DROP TABLE table--

Что означает, что наша строка запроса выглядит следующим образом:

INSERT INTO table (column, column2) VALUES ('Eve\', \"0\"); DROP TABLE table--}', "0")

Что хорошо! Данные, введенные пользователем, будут сохранены в базе данных по мере их ввода. Не без кавычек и не с дополнительными обратными слешами, но так, как они вошли. Это важно . Если вы храните данные любым другим способом, позже у вас возникнут проблемы с де-экранированием или двойным экранированием. Кроме того, добавление дополнительных косых черт или чего-либо подобного часто приводит к тому, что пользователи так или иначе оказываются открытыми для пользователей, и это гигантский предупреждающий знак того, что вещи не могут быть экранированы должным образом. Вы хотите избежать неправильных действий и особенно хотите избежать неправильных действий и рекламы об этом, что приводит меня к следующему разделу:

Альтернативы экранированию ваших данных

  1. Магические кавычки. Как вы заметили, не рекомендуется (и не без оснований) избегать.
  2. Не избегайте ваших данных. Я бы посоветовал против этого варианта.
  3. Убрать плохие символы из ввода. Раздражает почти во всех ситуациях, вы должны хранить то, что вводят пользователи, а не то, что технически легко хранить.
  4. Запретить ввод плохих символов. Иногда приемлемо (поля номера кредитной карты не должны обрабатывать кавычки), иногда раздражает, иногда массивный предупреждающий знак (например, в поле пароля)
  5. Подготовленные заявления. Я сказал, что «заполнение» переменных в строке было сделано PHP, а MySQL просто получал строку запроса, отсюда и необходимость экранирования. Подготовленные операторы разгрузят эту работу, будучи немного более умными, а использование подготовленных операторов будет выглядеть примерно так (предупреждение: псевдокод):

    $ Statement = $ db-> prepare ('INSERT INTO table (column, column2) VALUES ("% 1", "% 2")'); $ результат = $ оператор-> выполнить ($ значение1, $ значение2);

Есть хороший вопрос StackOverflow о методах экранирования SQL и ответы там углубляются, так что вы можете прочитать это.

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

$db->prepare('INSERT INTO table VALUES('.$value.')'))

Готово. На мой взгляд, это проще, чем отслеживать, какие переменные очищены, а какие нет. Некоторым людям нравится избегать строк, как только они приходят от пользователя, но это очень неловко, если они могут перейти куда-либо, кроме базы данных - обратно в HTML, в memcache и т. Д. Если вы собираетесь сделать это самостоятельно, я мог бы предложить несколько венгерских обозначений, например:

$uValue = $_POST['value'];
$sValue = escape($uValue);
$db->query('INSERT INTO table VALUES(' . $sValue .')');

Впервые я увидел эту идею в отличной статье Как сделать неправильный код неправильным Джоэлем Спольски.

Заключение

Надеюсь, вы чувствуете себя лучше подготовленными к созданию инъекционных сайтов. Удачи с любым выбранным вами методом и получайте удовольствие, всегда избегая ввода данных пользователем до того, как он попадет в базу данных! ;)

10 голосов
/ 01 февраля 2011

Это правильное поведение, оно работает!Кавычки экранируются в запросе, а не в базе данных.\ 'в запросе SQL должен быть преобразован в' внутри базы данных.Вы избегаете строк, так что SQL-запрос не запутывается и позволяет вводить кавычки в базу данных без SQL-запроса, интерпретирующего их как управляющие символы.

Ваш экранированный запрос будет:

mysql_query("INSERT INTO table (column, column2) VALUES ('It\'s time', "0")");

Данные в вашей базе данных должны быть "Время пришло".

Если бы оно не было сброшено, это было бы:

mysql_query("INSERT INTO table (column, column2) VALUES ('It's time', "0")");

Это выдаст ошибку относительно "времени" (потому чтоон будет интерпретировать только до следующего символа кавычки и будет видеть только «Это».) И «Время пришло!»это просто безобидная нить, но множество атак может произойти из этого, если вы не избежите своих персонажей.

0 голосов
/ 01 февраля 2011

mysql_real_escape_string () обычно достаточно для предотвращения SQLI.
Вы также должны фильтровать числовые значения, которые вы получаете от пользователя (используя intval ()).

...