Предотвращение внедрения SQL с использованием ТОЛЬКО php - PullRequest
6 голосов
/ 26 января 2011

Смысл в том, что у меня есть полноценный работающий веб-сайт с множеством обращений к серверу MySQL и, проводя некоторые исследования на этом сайте, я обнаружил, что делаю мои запросы в этой форме:

$query = sprintf("SELECT * FROM users WHERE user='%s' AND password='%s'",
            mysql_real_escape_string($user),
            mysql_real_escape_string($password));

Я могу решить проблему безопасности, но, как я уже сказал, у меня много обращений к серверу MySQL, и лучший способ (в моем случае) решить эту проблему - перейти непосредственно к переменным, которые я передаю в запрос, но без использования функции MySQL, потому что я вне запроса. Позвольте мне объяснить это, у меня есть это:

mysql_query("SELECT * FROM `post` WHERE id=" . $_GET['edit']);

Я не могу внести изменения в этот запрос, потому что у меня есть много всего этого в коде, поэтому я предпочитаю проверять наличие инъекций в var, $ _GET ['edit'].

Как я могу использовать чистую проверку PHP для SQL-инъекций в переменные запросов? Как:

$_GET['edit']=freehack($_GET['edit']);

Ответы [ 6 ]

12 голосов
/ 26 января 2011

Не делай так. Заменив значение ваших $_GET параметров на «безопасные» версии, вы загрязняете свои входные данные, которые могут вам понадобиться в других местах.

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

В любом случае, то, что вы делаете, все еще небезопасно! См .: PHP: Достаточно ли mysql_real_escape_string для очистки ввода пользователя?

Вы действительно должны использовать подготовленные запросы с PDO . Кроме того, вам следует проверять правильность введенных пользователем данных, прежде чем использовать их в запросе.

7 голосов
/ 26 января 2011

«Я не могу вносить изменения в этот запрос, потому что у меня есть много всего этого в коде» - это неправильное отношение к разговору о безопасности.То, что у вас есть, является серьезной проблемой проектирования, которая открывает вам все виды проблем безопасности.Даже если вы сделаете что-то наподобие метода фильтра, который вы описали в конце, вы не можете быть уверены, что будете охватывать каждый случай.

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

1 голос
/ 26 января 2011

Я думаю, вы могли бы заключить ваш запрос в PDO .

$unsafe = "SELECT * FROM `post` WHERE id=" . $_GET['edit'];
$DBH->quote($unsafe); // makes query safe.

где $DBH = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass);

Затем вам нужно написать какие-то сценарии для выполненияЗатем я действительно думаю, что вы должны переписывать свой код с нуля, потому что он действительно ужасен.Правильно проверенный модуль, PDO, CSRF-защита, OOP и т. Д.

0 голосов
/ 26 января 2011
  1. Избегайте повторения одного и того же запроса в разных местах в вашем приложении - по мере того, как дела растут, вам приходится поддерживать несколько версий, и они почти всегда не синхронизируются. Подготовленные запросы звучат хорошо для меня (я не очень-то разбираюсь в PHP), или, если вам нужно пойти другим путем, настройте центральную справочную библиотеку и храните там свои запросы, а затем ссылайтесь на них, когда они нужны в вашем приложении. 1003 *

  2. Не храните закодированные данные, слишком легко забыть, какие переменные закодированы, а какие нет, плюс у вас возникнут проблемы, как только вы будете использовать свои данные для целей с другой кодировкой , Кодируйте как можно позже в процессе, в идеале, когда он попадает в окончательную ситуацию, когда ему нужно кодирование, чтобы быстрая проверка показала, что это делается.

  3. Если вам нужно .... SQL-инъекция - это проблема безопасности типов. Если вы знаете, что ожидаете целочисленный параметр, «1; удалить таблицу; -», ввод недопустим, даже если в нем нет символов опасности или escape-последовательностей. Не просто проверяйте наличие строк или чего-либо еще, убедитесь, что, когда вам нужен определенный тип, вы получите этот, а другие входные данные выдают ошибку.

0 голосов
/ 26 января 2011

Я бы рекомендовал использовать интерфейс PDO или интерфейс MySQLi , так как оба поддерживают использование подготовленных запросов. Использование подготовленных запросов - единственный способ снова и снова эффективно защитить себя от атак SQL-инъекций. Я лично рекомендую PDO поверх mysqli, поскольку он обеспечивает независимый от базы данных интерфейс для вашей базы данных на случай, если вам когда-нибудь понадобится переключить базы данных. Даже если вам никогда не нужно переключать базы данных, лучше всего изучить только 1 интерфейс на тот случай, если вам нужно будет работать над другим проектом с использованием другой базы данных.

0 голосов
/ 26 января 2011

Я бы не пошел с «волшебной» функцией и не ожидал, что она очистит переменные. Это не решит весь крайний случай и все равно будет уязвимо.

Хороший пример этого - ваш второй запрос. Он все еще уязвим для SQL-инъекций , даже , если вы mysql_real_escape_string $_GET['edit'] переменная.

Вам нужно проверить все полученные данные и проверить, ожидаете ли вы того типа данных.

if (SomeValidator::validateInt($_GET['edit'])) {
    // OK, we continue //
} else {
    // Display error, but don't continue ! //
}

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

Если вы хотите получить правильные результаты проверки и очистки, вы можете использовать ESAPI для PHP .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...