Verification: a143cc29221c9be0

Mysqli query php примеры select where

Что такое SQL-уязвимость?

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




Причины допущения SQL уязвимости

Чтобы исключить возможность взлома баз данных при помощи SQL, необходимо знать, по каким причинам облегчается доступ к файлам. На самом деле, причины допущения уязвимости наиболее часто встречаются у новичков, которые совершают одни и те же ошибки. Наиболее часто к этому относится:

  • недостаточное экранирование пользовательских данных;
  • старое программное обеспечение (необходимо постоянно следить за обновлениями);
  • неправильно настроены права и фильтрация ввода;
  • включен вывод ошибок на «рабочей» системе.

Чтобы снизить вероятность допущения взлома при помощи SQL injection, необходимо исключить вышеперечисленные причины уязвимости баз данных. В первую очередь важно следить за обновлениями ПО и постоянно устанавливать последние версии программ. При составлении кода особое внимание важно уделять безопасности. После каждого крупного обновления желательно проводить полноценный аудит безопасности.




Виды SQL уязвимости

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

  • Union-based;
  • Error-based;
  • Blind (бывает двух видов: Boolean-based и Time-based).

Первый вариант подразумевает под собой то, что к конструкции UNION добавляется код SQL, который способен объединить результаты нескольких запросов. Но есть несколько требований к этим запросам: во-первых, у них должно быть одинаковое количество столбцов, во-вторых, эти столбцы должны быть одинакового типа.


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


Последний вариант SQL уязвимости подразумевает под собой, что результат мошенник получает по косвенным признакам. Как уже было сказано выше, эта разновидность SQL инъекции делится на два вида. Time-based отличается от Boolean-based только тем, что результат мошенник определяет по времени задержки ответа.




Примеры уязвимых PHP скриптов к SQL инъекции

Начнем с классики. Самая обыкновенная SQL уязвимость в процессе аутентификации.
Проблема заключается в том, что злоумышленник может в качестве логина или пароля ввести специальные символы SQL, которые не ожидаются от пользователя. Таким образом, злоумышленник изменит сам SQL запрос и нарушится логика веб-приложения.


Например, если злоумышленник в пароле выйдет из одинарной кавычки, подставив свою, то он может ввести свою логику в SQL запрос, например: "ANYPASSWORD' or 1=1 -- ".
Такая проверка всегда будет возвращать "истино", не зависимо от введеного пароля, если конечно пользователь существует и в итоге злоумышленник получит: 'Вы авторизировались под аккаунтом admin'.




Пример Blind SQL Injection (Time-based)

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

в основном бинарный поиск для получения информации из базы данных

.

Техника Time-Based основана на работе со временем, к примеру если злоумышленник введет в качестве пароля следующий код: "demo'-BENCHMARK(55555555, rand()) -- ", то MySQL выполнит функцию BENCHMARK очень много раз.
Такой SQL запрос будет выполняться пару секунд, благодаря этому можно предположить, что SQL уязвимость присутствует.




Последствия от SQL уязвимости

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

Также мошенник может сделать DOS сайта (отказ в обслуживании клиентов сайта), либо Deface (на сайте размещается посторонняя реклама, вирусные ссылки или даже замена экрана какой-нибудь картинкой или даже угрозой).

Кроме того, посторонние пользователи могут постараться получить доступ к остальным серверам в этой локальной сети или использовать «захваченный» сервер для майнинга криптовалюты.

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




Защита от SQL уязвимости

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




Ответ 1

Первое, что нужно сделать, это, вероятно, заменить каждый mysql_* вызов функции на его эквивалент mysqli_*, по крайней мере, если вы хотите использовать процедурный API, что было бы проще, учитывая, что у вас уже есть код на основе MySQL API, который является процедурным.

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

Например:

  • mysql_connect будет заменен на mysqli_connect

  • mysql_error будет заменен на mysqli_error и/или mysqli_connect_error, в зависимости от контекста

  • mysql_query будет заменен на mysqli_query

  • и так далее

Примечание: для некоторых функций вам может потребоваться тщательно проверить параметры: возможно, есть некоторые различия здесь и там, но не так много, я бы сказал: и mysql, и mysqli основаны на одной и той же библиотеке (libmysql; по крайней мере для PHP .

Например:

  • с mysql вы должны использовать mysql_select_db один раз для подключения, чтобы указать, к какой базе данных вы хотите выполнять свои запросы;

  • mysqli, с другой стороны, позволяет вам указать это имя базы данных в качестве четвертого параметра для mysqli_connect;

  • тем не менее есть также функция mysqli_select_db, которую вы можете использовать, если хотите.


Как только вы закончите с этим, попробуйте запустить новую версию вашего скрипта. 

Ответ 2

Полное руководство по обновлению mysql_* функций на MySQLi API

Причина создания нового расширения mysqli заключалась в том, чтобы воспользоваться преимуществами новых функций, имеющихся в системах MySQL версии 4.1.3 и новее. При изменении существующего кода с mysql_* API на mysqli вы должны воспользоваться этими улучшениями, иначе ваши усилия по обновлению могут быть напрасными.

Расширение mysqli имеет ряд преимуществ, по сравнению с расширением mysql:

  • Объектно-ориентированный интерфейс

  • Поддержка подготовленных отчетов

  • Расширенные возможности отладки

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

1. Объектно-ориентированный интерфейс вместо процедурных функций

Новый объектно-ориентированный интерфейс mysqli является большим улучшением по сравнению со старыми функциями и может сделать ваш код более чистым и менее подверженным синтаксическим ошибкам. Существует также процедурная версия этого API, но ее использование не рекомендуется, так как это приводит к менее читаемому коду, который более подвержен ошибкам.

Чтобы открыть новое соединение с базой данных с MySQLi, вам необходимо создать новый экземпляр класса MySQLi.

$mysqli = new \mysqli($host, $user, $password, $dbName);

$mysqli->set_charset('utf8mb4');

В процедурном стиле это будет выглядеть так:

$mysqli = mysqli_connect($host, $user, $password, $dbName);

mysqli_set_charset($mysqli, 'utf8mb4');

Имейте в виду, что только первые 3 параметра такие же, как в mysql_connect. Тот же код в старом API будет:

$link = mysql_connect($host, $user, $password);

mysql_select_db($dbName, $link);

mysql_query('SET NAMES utf8');

Если ваш PHP-код полагался на неявное соединение с параметрами по умолчанию, определенными в php.ini, теперь вам нужно открыть соединение MySQLi, передав параметры в вашем коде, а затем предоставить ссылку на соединение для всех процедурных функций или использовать стиль ООП.

2. Поддержка подготовленных отчетов

Это большой вопрос. MySQL добавил поддержку собственных подготовленных операторов в MySQL 4.1. Подготовленные операторы лучший способ предотвратить SQL-инъекцию. Было вполне логично, что в PHP была добавлена поддержка собственных подготовленных операторов. Подготовленные операторы следует использовать всякий раз, когда данные должны быть переданы вместе с вызовом SQL (то есть WHEREINSERT или UPDATE обычные случаи использования).

В старом MySQL API была функция для экранирования строк, используемых в вызываемом SQL mysql_real_escape_string, но она никогда не предназначалась для защиты от SQL-инъекций и, естественно, не должна использоваться для этой цели.
Новый MySQLi API предлагает заменяющую функцию mysqli_real_escape_string для обратной совместимости, которая имеет те же проблемы, что и старый код, и поэтому не должна использоваться, если подготовленные операторы недоступны.

Старый способ mysql_*:

$login = mysql_real_escape_string($_POST['login']);

$result = mysql_query("SELECT * FROM users WHERE user='$login'");

Подготовленный способ:

$stmt = $mysqli->prepare('SELECT * FROM users WHERE user=?');

$stmt->bind_param('s', $_POST['login']);

$stmt->execute();

$result = $stmt->get_result();

Подготовленные операторы в MySQLi могут показаться немного сложными для новичков. Если вы начинаете новый проект, то хорошей идеей может быть решение использовать более мощный и простой PDO API.

3. Расширенные возможности отладки

Некоторые PHP-разработчики старой школы привыкли проверять ошибки SQL вручную и отображать их прямо в браузере в качестве средства отладки. Однако такая практика оказалась не только громоздкой, но и опасной. К счастью, в MySQLi улучшены возможности создания отчетов об ошибках.

MySQLi может сообщать о любых обнаруженных ошибках как об исключениях PHP. Исключения PHP будут всплывать в скрипте и, если их не обрабатывать, немедленно прекратят его, что означает, что ни один оператор после ошибочного никогда не будет выполнен. Исключение вызовет фатальную ошибку PHP и будет вести себя как любая ошибка, вызванная ядром PHP в соответствии с display_errors и с log_errors настройками. Чтобы включить исключения MySQLi, используйте строку mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT) и вставьте ее прямо перед открытием соединения с БД.

mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);

$mysqli = new \mysqli($host, $user, $password, $dbName);

$mysqli->set_charset('utf8mb4');

Если вы привыкли писать такой код, как:

$result = mysql_query('SELECT * WHERE 1=1');

if (!$result) {

    die('Invalid query: '.mysql_error());

}

или же:

$result = mysql_query('SELECT * WHERE 1=1') or die(mysql_error());

вам больше не нужно вызывать die() в вашем коде.

mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);

$mysqli = new \mysqli($host, $user, $password, $dbName);

$mysqli->set_charset('utf8mb4');

$result = $mysqli->query('SELECT * FROM non_existent_table');

// Следующая строка никогда не будет выполнена из-за выброшенного выше исключения mysqli_sql_exception

foreach ($result as $row) {

    // ...

}

Если по какой-то причине вы не можете использовать исключения, MySQLi имеет эквивалентные функции для поиска ошибок. Можно использовать mysqli_connect_error() для проверки ошибок подключения и mysqli_error($mysqli) для любых других ошибок. Обратите внимание на обязательный аргумент mysqli_error($mysqli) или в качестве альтернативы придерживайтесь стиля и использования ООП $mysqli->error.

$result = $mysqli->query('SELECT * FROM non_existent_table') or trigger_error($mysqli->error, E_USER_ERROR);

4. Прочие изменения

К сожалению, не каждая функция from mysql_* имеет свой аналог в MySQLi только с добавлением «i» в имени и ссылке на соединение в качестве первого параметра. Вот список некоторых из них:

  • mysql_client_encoding() был заменен на mysqli_character_set_name($mysqli)

  • mysql_create_db не имеет аналогов. Используйте подготовленные операторы или mysqli_query вместо этого

  • mysql_drop_db не имеет аналогов. Используйте подготовленные операторы или mysqli_query вместо этого

  • mysql_db_namemysql_list_dbs поддержка была прекращена в пользу SQL SHOW DATABASES

  • mysql_list_tables поддержка была прекращена в пользу SQL SHOW TABLES FROM dbname

  • mysql_list_fields поддержка была прекращена в пользу SQL SHOW COLUMNS FROM sometable

  • вместо mysql_db_query->, используйте mysqli_select_db() или укажите имя БД в запросе

  • в mysql_fetch_field($result, 5)-> нет второго параметра (смещения) в mysqli_fetch_field. Вы можете использовать mysqli_fetch_field_direct, имея в виду разные возвращаемые результаты

  • mysql_field_flagsmysql_field_lenmysql_field_namemysql_field_tablemysql_field_type-> заменено на mysqli_fetch_field_direct

  • mysql_list_processes был удален. Если вам нужен идентификатор потока, используйте mysqli_thread_id

  • mysql_pconnect был заменен на mysqli_connect() с p:префиксом хоста

  • в mysql_result-> используйте mysqli_data_seek()  вместе с mysqli_field_seek() и mysqli_fetch_field()

  • mysql_tablename поддержка была прекращена в пользу SQL SHOW TABLES

  • mysql_unbuffered_query был удален