Уязвимость форматной строки в PHP extmysqli


Оглавление (нажмите, чтобы открыть):

Уязвимости PHP (устаревшего) модуля mysql против MySQLi и PDO

Я занимаюсь поддержкой и расширением базы PHP-кода, которая началась в 2007 году и использует оригинальный модуль mysql . Все пользовательские вводятся с помощью литья для значений, которые, как ожидается, будут численными, mysql_real_escape_string() цитируются с использованием одинарных кавычек для строк, возможно, дополнительно фильтруются через поля in_array() для ENUM или array_intersect() для полей SET . Все строки с неограниченной строкой передаются через htmlspecialchars() или htmlentities() при выводе HTML. Если значение представляет собой внешний ключ, этот ключ сначала проверяется. Я считаю, что, строго следуя этим процедурам, приложение настолько же безопасно, как и против инъекций и других форм атаки. (бонусные баллы: я прав? Если нет, то что мне не хватает?)

Преобразование этого приложения в mysqli или PDO было бы довольно большой задачей (и, во избежание случайного поломки, не то, что я хотел бы автоматизировать). Итак, наконец, на мой вопрос: Существуют ли какие-либо конкретные уязвимости, которые не могут быть устранены при использовании старого модуля mysql , который требует перехода на более новые модули?

Информация о Bounty:
Чтобы быть ясным, я надеюсь на список CVE-номеров или выражение разработчиков PHP о том, что модуль mysql исправлен против всех известных уязвимостей, таких как дата-дата. Я также предполагаю, что после использования лучших современных методов использования модуля я не предоставляю дополнительные атак. BCP уже включают экранирование данных, взятых из db, прежде чем вставлять их в новый оператор. Продолжение и повторение этого вопроса на самом деле не затрагивает вопрос.

У меня есть только 2 возражения

  • All user input is escaped является критической ошибкой, приводящей к во втором заказе. «Все динамические данные для SQL» — это правильный подход и фразировка
  • в вашем сообщении нет identifiers, но я не могу поверить, что у вас нет запроса с динамическим идентификатором в вашем с 2007 года.

Есть и незначительные неудобства: через пару лет (возможно, 3-4) ваш PHP начнет выдавать ошибки уровня E_DEPRECATED. Но их можно просто отключить.

В любом случае, просто механический переход от одного API к другому не будет иметь особого смысла.
Рефакторинг вашего кода обработки SQL только для использования некоторого механизма абстракции, будь то ORM, AR, QueryBuilder или любой другой технологии, которая будет стереть необработанные вызовы API из кода приложения. Это не только сделает ваш код менее раздутым, но и сделает его независимым от любой другой прихоти, которая в будущем поразит разработчиков PHP.

Чтобы ответить на отредактированный вопрос.

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

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

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

Я бы предложил рефакторинг. Период. Просто сделай это. Имейте в виду рефакторинг, и не изменяйте или не расширяйте свою кодовую базу при этом — это неприятная ловушка. Несмотря на то, что это будет какая-то работа — рефакторинг, просто начните процесс рефакторинга (разветвленный, конечно). Это будет очень удовлетворительно при завершении. Ожидайте некоторые проблемы с длинным хвостом.

Я предполагаю, что все функциональные возможности, которые вы описываете, уже завернуты, поэтому рефакторинг должен быть достаточно выполнимым. Если вещи не были завернуты.. ($ # @!), Определите способ однозначного отслеживания вызовов функций (включая контекст) по всему проекту (возможно, используя регулярные выражения в поиске их всех) и замените их новыми уникальными функциями, be-used wrapper. Сначала исследуйте это, тщательно. Через пол дня вы сможете заручиться всем своим регулярным выражением, которое вам понадобится. Поэтому сначала планируйте его, сначала исследуя свой путь.

Заполните новые обертки текущим (старым) функциональным кодом и посмотрите, все ли работает, как было.

Затем начните миграцию в mysqli и внутренне перестройте свои обертки.

Кажется, что это простой, по возможности подход, избегая всех вопросов и вопросов, которые останутся в глубине вашего ума, несмотря на то, что вы пытаетесь сделать, взломав свой путь глубже вокруг обычного mysql. Мне не нужно рассказывать о преимуществах, которые принесет mysqli, вы уже знаете это. Кроме того, это просто хорошая практика каждый раз, когда на самом деле берут на себя такие проблемы раз и навсегда. Планируйте, обсудите, ответьте, попробуйте, сделайте, испытайте, заполните и победите! В довершении всего: убедитесь, что вы не можете использовать возможности расширения вашей базы кода и функциональной области при рефакторинге — у вас возникнет соблазн сделать это: просто рефакторинг. Добавьте, расширьте или улучшите позже.

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

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

EDIT в ответ на справедливый комментарий YCs ниже: во избежание двусмысленности я всегда ставил все, что пользователь создал через подготовленный оператор, даже если он уже был сохранен в db. По возможности я избегаю повторной установки пользовательских данных, хотя, поскольку это ненадежно, поэтому системные функции зависят от автоматически генерируемых индексов.

Справедливости ради, страницы коротки (не более 1000 строк), поэтому исправление не займет много времени на странице, и у них мало запросов, поэтому снижение производительности не заметно и, безусловно, съедено усовершенствованиями в серверной технологии, так как я написал исходный код. Я подозреваю, что вы обнаружите, что сокращение экранирования и т.д. Значительно перевешивает любой удар производительности в операциях prep, хотя вам придется проверить, не критично ли это.

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

Способ, которым я собираюсь изменить, — добавить соединение mysqli к моему основному файлу базы данных. Все это использует новый код. Когда я нахожу время, я обновляю старый код и тестирую каждую страницу, используя заголовочный файл, у которого нет старого соединения mysql. Он мертв быстро, чтобы найти бит, который вы пропустили таким образом в среде Dev, и это может быть довольно хороший способ использовать время, которое иначе было бы потрачено впустую, поскольку каждая страница занимает всего несколько минут для обновления, поэтому это можно сделать во время угасания мозга периоды.

Заметка о закачке второго порядка BTW, поскольку это была самая распространенная уязвимость, которую я создал:

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

Можно предположить, что код может быть введен через вашу защиту, а затем использоваться позже. Это вряд ли будет работать, поскольку оно сильно зависит от неуклюжий db и дизайна приложения, но некоторые из самых умных людей в мире — это хакеры. Зачем облегчать их жизнь?

Атака становится более вероятной, если ваш sql прост, и ваше приложение выполняет любой подзапрос, используя данные, ранее полученные из db. Помните, что

поэтому, если он был извлечен и помещен в переменную PHP, которая затем используется в запросе sql, который не используется, он может вызвать проблемы точно так же, как если бы он никогда не был экранирован. Если вы просто используете операторы prep для всех запросов, риск уходит навсегда, хотя помните, что инструкция prep все еще хранит вредоносный код, поэтому вам все равно придется снова использовать подготовленный оператор, когда вам нужно будет использовать введенные данные.

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

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

mysqli_stmt::fetch — Связывает результаты подготовленного выражения с переменными

mysqli_stmt_fetch

mysqli_stmt::fetch — mysqli_stmt_fetch — Связывает результаты подготовленного выражения с переменными

Описание

Связывает результаты подготовленного выражения с переменными, определенными с помощью mysqli_stmt_bind_result() .

Необходимо отметить, что все столбцы должны быть связаны перед вызовом mysqli_stmt_fetch() .

Данные не буферизуются при передаче когда вызывается mysqli_stmt_store_result() , что снижает производительность (но также снижает затраты памяти).

Список параметров

Только для процедурного стиля: Идентификатор выражения, полученный с помощью mysqli_stmt_init() .

Возвращаемые значения

Возвращаемые значения

Значение Описание
TRUE Успех. Данные были выбраны
FALSE Произошла ошибка
NULL Больше нет строк/данных или произошло усечение данных

Примеры

Пример #1 Объектно-ориентированный стиль

= new mysqli ( «localhost» , «my_user» , «my_password» , «world» );

/* Проверить соединение */
if ( mysqli_connect_errno ()) <
printf ( «Попытка соединения не удалась: %s\n» , mysqli_connect_error ());
exit();
>

$query = «SELECT Name, CountryCode FROM City ORDER by ID DESC LIMIT 150,5» ;

if ( $stmt = $mysqli -> prepare ( $query )) <

/* Запустить выражение */
$stmt -> execute ();

/* Определить переменные для результата */
$stmt -> bind_result ( $name , $code );

/* Выбрать значения */
while ( $stmt -> fetch ()) <
printf ( «%s (%s)\n» , $name , $code );
>

/* Завершить запрос */
$stmt -> close ();
>

/* Закрыть соединение */
$mysqli -> close ();
?>

Пример #2 Процедурный стиль

= mysqli_connect ( «localhost» , «my_user» , «my_password» , «world» );

/* Проверить соединение */
if ( mysqli_connect_errno ()) <
printf ( «Попытка соединения не удалась: %s\n» , mysqli_connect_error ());
exit();
>

$query = «SELECT Name, CountryCode FROM City ORDER by ID DESC LIMIT 150,5» ;

if ( $stmt = mysqli_prepare ( $link , $query )) <

/* Запустить запрос */
mysqli_stmt_execute ( $stmt );

/* Определить переменные для результата */
mysqli_stmt_bind_result ( $stmt , $name , $code );

/* Выбрать значения */
while ( mysqli_stmt_fetch ( $stmt )) <
printf ( «%s (%s)\n» , $name , $code );
>

/* Завершить запрос */
mysqli_stmt_close ( $stmt );
>

/* Закрыть соединение */
mysqli_close ( $link );
?>

Результат выполнения данных примеров:

Смотрите также

  • mysqli_prepare() — Подготавливает SQL выражение к выполнению
  • mysqli_stmt_errno() — Возвращает код ошибки выполнения последнего запроса
  • mysqli_stmt_error() — Возвращает строку с пояснением последней ошибки при выполнении запроса
  • mysqli_stmt_bind_result() — Привязка переменных к подготовленному запросу для размещения результата

Основы работы с PHP MySqli

В связи с прекращением поддержки PHP MySQL в 2011 году для работы с базами данных все более широкое применение находят PDO или MySqli. Они обладают лучшей функциональностью (чем MySQL) и предлагают ООП (объектно-ориентированный интерфейс) API. Какой из них лучше, это тема для другой статьи, в этой статье мы попытаемся разобраться с основами работы с MySqli. Поэтому, без дальнейших предисловий, перейдем к рассмотрению соединения ( connect ), выбора ( select ), вставки ( insert ), обновления ( update ) и удаления ( delete ) записей (данных/документов/информации) посредством PHP MySqli. Надеюсь, что данная статья будет полезна при решении проблем, которые могут возникнуть при работе с PHP MySqli.

Установка MySqli

При использовании PHP версии 5.3.0 +, MySqli доступен по умолчанию; для более старых версий, чтобы сделать его доступным, надо включить php_mysqli.dll DLL внутри файла php.ini и отредактировать php.ini, раскоментировав строчку extension=php_mysqli.dll . В линуксе MySQLIi будет установлен автоматически при установке пакета PHP5 mysql. Более подробную информацию об установке в системах windows и linux можно найти здесь.

Соединение с базой данных

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

Ниже показано открытие соединения с базой данных объектно-ориентированным способом. Этот способ будет использоваться и во всех приведенных ниже примерах.

Выбор (SELECT) результирующего ряда в виде ассоциативного массива

mysqli_fetch_assoc() : в приведенном ниже коде происходит извлечение результирующего ряда в виде ассоциативного массива. Возвращаемый массив содержит строки, полученные из базы данных, где имена столбцов будут являться ключом, используемым для доступа к внутренним данным. Как показана ниже, данные отображаются в виде HTML таблицы.

Выбор (SELECT) результирующего ряда в виде массива (ассоциативный, обычный, или в оба)

Фукнция fetch_array() : возвращает массив с объединенным функционалом mysqli_fetch_row и mysqli_fetch assoc . Эта функция является расширенной версией функции mysqli_fetch_row() ; для доступа к данным можно использовать как строку, так и числа.

Выбор (SELECT) результирующего ряда в виде объекта

fetch_object() : чтобы получить результирующий набор в виде объекта, нужно воспользоваться MySqli fetch_object() . Атрибуты объекта будут отображать имена полей, найденных внутри результирующего набора.

Выбор (SELECT) одиночного значение

Одиночное значение получить из базы данных можно посредством fetch_object (метод Cameron Spear).

Извлекаем (SELECT COUNT) количество строк в таблице

Иногда нужно узнать количество строк в таблице, особенно при нумерации страниц.

Выбор (SELECT) с помощью шаблонов (prepared statements)

prepared statements — специальный инструмент СУБД, позволяющий ускорить последовательное выполнение повторяющихся запросов, построенных по одному и тому же шаблону.

Одной из особенностей MySqli является возможность использования уже написанных шаблонов: то есть запрос достаточно написать один раз, после чего его можно многократно исполнять с различными параметрами. Использование уже написанных шаблонов улучшает производительность для больших таблицах и сложных запросов. Для предотвращения попадания вредоносного кода анализ каждого запроса производится сервером отдельно.

Код ниже использует шаблон (Prepared statement), чтобы получать данные из базы данных. Заполнитель ? в запросе SQL играет роль маркера и будет замещен параметром, который, в свою очередь, может быть строкой, целым числом, double или blob. В нашем случае это строка $search_product .

Тот же запрос с несколькими параметрами:

Вставка (INSERT) записи

Запись ниже вставляет в таблицу новый ряд.

Отрывок ниже вставляет те же значения посредством шаблонов (Prepared Statement). Как мы уже говорили, шаблоны чрезвычайно эффективны против SQL инъекция. Для приведенного примера их использование является оптимальным вариантом.

Вставка (INSERT) нескольких записей

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

Обновление (Update)/удаление (Delete) записей

Принцип обновление и удаление записей тот же. Достаточно заменить строку запроса на MySql update или delete (не понял, сам смотри).

Обновление с помощью шаблонов (prepared statements)

Пример обновления записи с помощью шаблонов (prepared statements) приведен ниже.

Удаление старых записей

Удалению подвергаются все записи, находящиеся на сервере больше 1 дня; количество дней можно задать самому.

Заключение

Вне сомнения, MySqli существенно лучше стандартного MySql расширения PHP, хотя принципы их работы довольно схожи. Надеюсь, приведенная выше информация окажется полезной при создании и переносе проектов в будущем. Для удобства ниже была реализована возможность скачать файлы примеров. Это можно сделать, нажав на кнопку download.

Почему я не должен использовать функции mysql_ * в PHP?

Каковы технические причины, почему не следует использовать mysql_* функции? (например. mysql_query() , mysql_connect() или же mysql_real_escape_string() )?

Почему я должен использовать что-то еще, даже если они работают на моем сайте?

Если они не работают на моем сайте, почему я получаю такие ошибки, как

Предупреждение: mysql_connect (): нет такого файла или каталога

Решение

  • Не находится в стадии активной разработки
  • Является официально осуждается по состоянию на PHP 5.5 (выпущен в июне 2013 года).
  • Был удален полностью начиная с PHP 7.0 (выпущено в декабре 2015 г.)
    • Это означает, что с 31 декабря 2020 г. он не будет существовать ни в одной поддерживаемой версии PHP. В настоящее время он получает только безопасность Обновления.
  • Отсутствует интерфейс OO
  • Не поддерживает:
    • Неблокирующие, асинхронные запросы
    • Подготовленные заявления или параметризованные запросы
    • Хранимые процедуры
    • Несколько заявлений
    • операции
    • «Новый» метод аутентификации по паролю (включен по умолчанию в MySQL 5.6; требуется в 5.7)
    • Все функциональные возможности в MySQL 5.1

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

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

Другие решения

PHP предлагает три разных API для подключения к MySQL. Эти mysql (удалено с PHP 7), mysqli , а также PDO расширения.

mysql_* Раньше функции были очень популярны, но их использование больше не поощряется. Команда разработчиков документации обсуждает ситуацию с безопасностью базы данных, и обучение пользователей отойти от широко используемого расширения ext / mysql является частью этого (проверьте php.internals: устарел ext / mysql ).

И более поздняя команда разработчиков PHP приняла решение генерировать E_DEPRECATED ошибки при подключении пользователей к MySQL через mysql_connect() , mysql_pconnect() или неявная функциональность подключения, встроенная в ext/mysql ,

Видишь красную коробку?

Когда вы идете на любой mysql_* На странице руководства функции вы видите красную рамку, объясняющую, что ее больше не следует использовать.

Зачем

Отойдя от ext/mysql речь идет не только о безопасности, но и о доступе ко всем функциям базы данных MySQL.

ext/mysql был построен для MySQL 3.23 и только с тех пор получил очень мало дополнений, сохраняя совместимость с этой старой версией, что усложняет поддержку кода. Отсутствуют функции, которые не поддерживаются ext/mysql включают: (из руководства по PHP ).


  • Хранимые процедуры (не может обрабатывать несколько наборов результатов)
  • Подготовленные заявления
  • Шифрование (SSL)
  • компрессия
  • Полная поддержка Charset

Причина не использовать mysql_* функция:

  • Не в стадии активной разработки
  • Удалено с PHP 7
  • Отсутствует интерфейс OO
  • Не поддерживает неблокирующие, асинхронные запросы
  • Не поддерживает подготовленные заявления или параметризованные запросы
  • Не поддерживает хранимые процедуры
  • Не поддерживает несколько утверждений
  • Не поддерживает операции
  • Не поддерживает все функции в MySQL 5.1

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

Подавление предупреждений об устаревании

Пока код конвертируется в MySQLi / PDO , E_DEPRECATED ошибки могут быть подавлены настройкой error_reporting в php.ini исключить E_DEPRECATED:

Обратите внимание, что это также будет скрывать другие предупреждения об устаревании, что, однако, может быть для вещей, отличных от MySQL. (из руководства по PHP )

И лучший способ PDO и сейчас я пишу простую PDO руководство.

Простое и краткое руководство по PDO

В. Первый вопрос, который у меня возник, был: что такое «PDO»?

А. «PDO — объекты данных PHP — это уровень доступа к базе данных, обеспечивающий единый метод доступа к нескольким базам данных ».

Подключение к MySQL

С mysql_* функция или мы можем сказать это по-старому (устарело в PHP 5.5 и выше)

С PDO : Все, что вам нужно сделать, это создать новый PDO объект. Конструктор принимает параметры для указания источника базы данных PDO Конструктор в основном принимает четыре параметра, которые DSN (имя источника данных) и опционально username , password ,

Здесь я думаю, что вы знакомы со всеми, кроме DSN ; это новое в PDO , DSN в основном это строка опций, которые говорят PDO какой драйвер использовать, и детали подключения. Для дальнейшего ознакомления, проверьте PDO MySQL DSN .

Замечания: Вы также можете использовать charset=UTF-8 , но иногда это вызывает ошибку, поэтому лучше использовать utf8 ,

Если есть какая-либо ошибка соединения, он выдаст PDOException объект, который можно поймать для обработки Exception в дальнейшем.

Вы также можете передать несколько параметров драйвера в виде массива к четвертому параметру. Я рекомендую передать параметр, который ставит PDO в режим исключения. Потому что некоторые PDO драйверы не поддерживают нативно подготовленные операторы, поэтому PDO выполняет эмуляцию приготовления. Это также позволяет вам вручную включить эту эмуляцию. Чтобы использовать собственные подготовленные операторы на стороне сервера, вы должны явно установить его false ,

Другой — отключить эмуляцию подготовки, которая включена в MySQL драйвер по умолчанию, но подготовка эмуляции должна быть отключена для использования PDO безопасно.

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

Это возможно только в том случае, если вы используете старую версию MySQL который я не рекомендовал.

Ниже приведен пример того, как вы можете сделать это:

Можем ли мы установить атрибуты после построения PDO?

да, мы также можем установить некоторые атрибуты после построения PDO с setAttribute метод:

Обработка ошибок

Обработка ошибок намного проще в PDO чем mysql_* ,

Обычная практика при использовании mysql_* является:

OR die() это не хороший способ справиться с ошибкой, так как мы не можем справиться с вещью в die , Он просто внезапно завершит выполнение сценария, а затем отобразит сообщение об ошибке, которое вы обычно НЕ хотите показывать своим конечным пользователям, и позволит кровавым хакерам обнаружить вашу схему. Альтернативно, возвращаемые значения mysql_* функции часто могут использоваться в сочетании с mysql_error () обрабатывать ошибки.

PDO предлагает лучшее решение: исключения. Все, что мы делаем с PDO должны быть завернуты в try — catch блок. Мы можем заставить PDO в один из трех режимов ошибок, установив атрибут режима ошибок. Три режима обработки ошибок приведены ниже.

  • PDO::ERRMODE_SILENT , Он просто устанавливает коды ошибок и действует почти так же, как mysql_* где вы должны проверить каждый результат, а затем посмотреть на $db->errorInfo(); чтобы получить подробности об ошибке.
  • PDO::ERRMODE_WARNING поднимать E_WARNING , (Предупреждения во время выполнения (не фатальные ошибки). Выполнение сценария не прекращается.)
  • PDO::ERRMODE_EXCEPTION : Выбросить исключения. Это представляет ошибку, выдвинутую PDO. Вы не должны бросать PDOException из вашего собственного кода. Увидеть Исключения для получения дополнительной информации об исключениях в PHP. Это очень похоже на or die(mysql_error()); , когда он не пойман. Но в отличие от or die() , PDOException может быть пойман и обработан изящно, если вы решите это сделать.

Хорошо для чтения:

И вы можете обернуть его в try — catch как показано ниже:

Вы не должны справляться с try — catch прямо сейчас. Вы можете поймать его в любое удобное время, но я настоятельно рекомендую вам использовать try — catch , Также может иметь смысл поймать его за пределами функции, которая вызывает PDO материал:

Кроме того, вы можете справиться с or die() или мы можем сказать, как mysql_* , но это будет действительно разнообразно. Вы можете скрыть опасные сообщения об ошибках в производстве, повернув display_errors off и просто читать ваш журнал ошибок.

Теперь, после прочтения всего вышесказанного, вы, вероятно, подумаете: что за черт, когда я просто хочу начать просто SELECT , INSERT , UPDATE , или же DELETE заявления? Не волнуйтесь, здесь мы идем:

Выбор данных

Так что вы делаете в mysql_* является:

Сейчас в PDO Вы можете сделать это следующим образом:

Заметка: Если вы используете метод, как показано ниже ( query() ), этот метод возвращает PDOStatement объект. Поэтому, если вы хотите получить результат, используйте его, как указано выше.

В данных PDO это получается через ->fetch() метод вашего оператора. Перед вызовом fetch лучше всего сообщить PDO, как вы хотите получать данные. В следующем разделе я объясняю это.

Режимы выборки

Обратите внимание на использование PDO::FETCH_ASSOC в fetch() а также fetchAll() код выше. Это говорит PDO вернуть строки в виде ассоциативного массива с именами полей в качестве ключей. Есть также много других режимов извлечения, которые я объясню один за другим.

Прежде всего, я объясню, как выбрать режим выборки:

Выше я использовал fetch() , Вы также можете использовать:

  • PDOStatement::fetchAll() — Возвращает массив, содержащий все строки набора результатов
  • PDOStatement::fetchColumn() — Возвращает один столбец из следующей строки набора результатов
  • PDOStatement::fetchObject() — Выбирает следующую строку и возвращает ее как объект.
  • PDOStatement::setFetchMode() — Установите режим выборки по умолчанию для этого оператора

Теперь я пришел к режиму выборки:

  • PDO::FETCH_ASSOC : возвращает массив, проиндексированный по имени столбца, как возвращено в вашем наборе результатов
  • PDO::FETCH_BOTH (по умолчанию): возвращает массив, проиндексированный как по имени столбца, так и по номеру столбца с 0 индексами, как возвращено в вашем наборе результатов

Есть еще больше вариантов! Читайте о них все в PDOStatement Получить документацию. .

Получение количества строк:

Вместо того, чтобы использовать mysql_num_rows чтобы получить количество возвращаемых строк, вы можете получить PDOStatement и делать rowCount() , лайк:

Получение последнего введенного идентификатора

Вставить и обновить или удалить заявления

Чем мы занимаемся mysql_* функция:

И в pdo то же самое можно сделать:

В приведенном выше запросе PDO::exec выполнить оператор SQL и возвращает количество затронутых строк.

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

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

Подготовленные заявления

Q. Что такое подготовленное заявление и зачем оно мне?
A. Подготовленный оператор — это предварительно скомпилированный оператор SQL, который можно выполнить несколько раз, отправив только данные на сервер.

Типичный рабочий процесс использования подготовленного оператора выглядит следующим образом (цитируется из википедии три 3 очка ):

Подготовить: Шаблон выписки создается приложением и отправляется в систему управления базами данных (СУБД). Некоторые значения не указываются, называются параметрами, заполнителями или переменными связывания (помечены ? ниже):

INSERT INTO PRODUCT (name, price) VALUES (?, ?)

СУБД анализирует, компилирует и выполняет оптимизацию запросов по шаблону оператора и сохраняет результат без его выполнения.

  • казнитьПозже приложение предоставляет (или связывает) значения для параметров, и СУБД выполняет оператор (возможно, возвращая результат). Приложение может выполнить инструкцию столько раз, сколько захочет, с разными значениями. В этом примере он может предоставить «Хлеб» для первого параметра и 1.00 для второго параметра.
  • Вы можете использовать подготовленный оператор, включив заполнители в ваш SQL. В основном есть три без заполнителей (не пытайтесь сделать это с переменной выше одной), один с неназванными заполнителями и один с именованными заполнителями.

    Q. Итак, как называются заполнители и как их использовать?
    A. Именованные заполнители. Используйте описательные имена, начинающиеся с двоеточия, вместо вопросительных знаков. Нас не волнует позиция / порядок значений в названии местозаполнителя:

    Вы также можете связать с использованием массива execute:

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

    Q. Итак, что же такое безымянные заполнители и как их использовать?
    A. Давайте приведем пример:

    В приведенном выше, вы можете увидеть те, ? вместо имени, как в названии местозаполнителя. Теперь в первом примере мы присваиваем переменные различным заполнителям ( $stmt->bindValue(1, $name, PDO::PARAM_STR); ). Затем мы присваиваем значения этим заполнителям и выполняем инструкцию. Во втором примере первый элемент массива переходит к первому ? и второй ко второму ? ,

    НОТА: В неназванные заполнители мы должны позаботиться о правильном порядке элементов в массиве, который мы передаем PDOStatement::execute() метод.

    SELECT , INSERT , UPDATE , DELETE подготовленные запросы

    SELECT :

    INSERT :

    DELETE :

    UPDATE :

    НОТА:

    тем не мение PDO и / или MySQLi не совсем безопасны. Проверьте ответ Достаточно ли подготовленных операторов PDO для предотвращения внедрения SQL? от ircmaxell . Также я цитирую некоторую часть из его ответа:

    Сначала давайте начнем со стандартного комментария, который мы даем всем:

    Давайте рассмотрим это, предложение за предложением, и объясним:

    Они больше не поддерживаются и официально устарели

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

    Новее! внутр / MySQL был удален в PHP 7 .

    Вместо этого вы должны узнать о готовых утверждениях

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

    Для получения дополнительной информации см. Как я могу предотвратить внедрение SQL в PHP?

    Видишь красную коробку?

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

    Используйте либо PDO, либо MySQLi

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

    Простота использования

    Аналитические и синтетические причины уже упоминались. Для новичков есть более существенный стимул прекратить использование устаревших функций mysql_.

    Современные API баз данных просто Полегче использовать.

    Это в основном связанные параметры который может упростить код. И с отличные учебники (как видно выше) переход к PDO не слишком сложно.

    Перезапись большей кодовой базы за один раз, однако, требует времени. Raison d’être для этой промежуточной альтернативы:

    Эквивалентные функции pdo_ * вместо mysql_ *

    С помощью Вы можете переключиться со старых функций mysql_ с помощью минимальное усилие. Добавляет pdo_ функциональные обертки, которые заменяют их mysql_ двойники.

    Просто include_once( «pdo_mysql.php» ); в каждом скрипте вызова, который должен взаимодействовать с базой данных.

    Удалить mysql_ префикс функции везде и заменить его на pdo_ .

    • mysql_ connect() становится pdo_ connect()
    • mysql_ query() становится pdo_ query()
    • mysql_ num_rows() становится pdo_ num_rows()
    • mysql_ insert_id() становится pdo_ insert_id()
    • mysql_ fetch_array() становится pdo_ fetch_array()
    • mysql_ fetch_assoc() становится pdo_ fetch_assoc()
    • mysql_ real_escape_string() становится pdo_ real_escape_string()
    • и так далее…

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

    И вуаля.
    Ваш код с помощью PDO.
    Теперь пришло время на самом деле использовать Это.

    Связанные параметры могут быть просты в использовании

    Вам просто нужен менее громоздкий API.

    pdo_query() добавляет очень легкую поддержку для связанных параметров. Преобразовать старый код просто:

    Переместите ваши переменные из строки SQL.

    • Добавьте их в качестве параметров функции, разделенных запятыми, в pdo_query() ,
    • Поместите вопросительные знаки ? в качестве заполнителей, где переменные были раньше.
    • Избавляться от ‘ одинарные кавычки, которые ранее заключены в строковые значения / переменные.

    Преимущество становится более очевидным для более длинного кода.

    Часто строковые переменные не просто интерполируются в SQL, а объединяются с экранированием вызовов между ними.

    С ? заполнители подали заявку, вам не нужно беспокоиться об этом:

    Помните, что pdo_ * все еще позволяет либо.
    Просто не экранируйте переменную а также привязать его в том же запросе.

    • Функция заполнителя обеспечивается настоящим PDO за ним.
    • Таким образом, также допускается :named списки заполнителей позже.

    Что еще более важно вы можете безопасно передавать переменные $ _REQUEST [] за любым запросом. Когда подано поля соответствуют структуре базы данных, она еще короче:

    Так много простоты. Но давайте вернемся к еще нескольким советам по переписыванию и техническим причинам, по которым вы можете избавиться от mysql_ и сбежать.

    Исправить или удалить любую oldschool sanitize() функция


    Как только вы преобразовали все mysql_ звонки в pdo_query со связанными параметрами, удалите все лишние pdo_real_escape_string звонки.

    В частности, вы должны исправить любые sanitize или же clean или же filterThis или же clean_data функции, заявленные датированными уроками в той или иной форме:

    Самая вопиющая ошибка здесь — отсутствие документации. Что еще более важно, порядок фильтрации был в неправильном порядке.

    Правильный порядок был бы: не рекомендуется stripslashes как внутренний вызов, то trim потом strip_tags , htmlentities для выходного контекста, и только в конце _escape_string так как его применение должно предшествовать промежуточному анализу SQL.

    Но в качестве первого шага просто избавиться от _real_escape_string вызов.

    Возможно, вам придется сохранить остальную часть вашего sanitize() пока, если ваша база данных и поток приложений ожидают строки, безопасные для контекста HTML. Добавьте комментарий, что отныне он применяет только HTML-код.

    Обработка строк / значений делегируется PDO и его параметризованным операторам.

    Если было какое-либо упоминание о stripslashes() в вашей функции дезинфекции это может указывать на более высокий уровень контроля.

    Это было обычно, чтобы отменить ущерб (двойной выход) из устарелых magic_quotes . Который однако лучше всего зафиксировано централизованно , не строка за строкой.

    Используйте один из изменение пользовательского пространства подходы. Затем удалите stripslashes() в sanitize функция.

    Историческая справка о magic_quotes. Эта функция по праву считается устаревшей. Это часто неправильно изображается как неудачный безопасность особенность однако. Но magic_quotes — такая же неудачная функция безопасности, как и теннисные мячи, как источник питания. Это просто не было их целью.

    Оригинальная реализация в PHP2 / FI представила это явно с помощью просто «кавычки будут автоматически экранированы, что упростит передачу данных формы непосредственно в запросы msql«. Это было случайно безопасно для использования с Msql , так как это поддерживает только ASCII.
    Затем PHP3 / Zend заново ввел magic_quotes для MySQL и неправильно его документировал. Но изначально это было просто удобная функция , не предназначено для безопасности.

    Чем отличаются готовые заявления

    Когда вы скремблируете строковые переменные в запросы SQL, вам не просто становится сложнее следовать. MySQL также постарается снова разделить код и данные.

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

    С помощью связанных параметров вы разделяете значения SQL-кода и SQL-контекста в вашем PHP-коде. Но он не зацикливается снова (за исключением PDO :: EMULATE_PREPARES). Ваша база данных получает неизменные команды SQL и значения переменных 1: 1.

    Хотя в этом ответе подчеркивается, что вы должны заботиться о читабельности mysql_ . Из-за этого видимого и технического разделения данных и кода иногда также появляется преимущество в производительности (повторяющиеся вставки с просто отличающимися значениями).

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

    Использование гибридного PDO

    Эти pdo_* Функции-обертки создают удобный для программирования API. (Это в значительной степени то, что MYSQLI могло бы быть, если бы не смещение сигнатуры уникальной функции). Они также чаще всего выставляют настоящий PDO.
    Перезапись не должна останавливаться на использовании новых имен функций pdo_. Вы можете по очереди переходить каждый pdo_query () в простой вызов $ pdo-> prepare () -> execute ().

    Однако лучше начать с упрощения. Например, общий результат выборки:

    Может быть заменено только итерацией foreach:

    Или, что еще лучше, прямой и полный поиск массивов:

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

    Другие опции

    Так что это, надеюсь, визуализировал некоторые практическое причины и достойный путь mysql_ .

    Просто переключаюсь на п.д.о. не совсем порезать это. pdo_query() это также просто интерфейс на него.

    Если вы не введете привязку параметров или не сможете использовать что-то еще из более приятного API, это бессмысленный переход. Я надеюсь, что это изображено достаточно просто, чтобы не способствовать разочарованию новичков. (Образование обычно работает лучше, чем запрет.)

    Несмотря на то, что он соответствует категории «самая простая вещь, которая может быть возможна», он также все еще является очень экспериментальным кодом. Я просто написал это на выходных. Однако существует множество альтернатив. Просто Google для PHP база данных абстракция и просмотр немного. Для таких задач всегда было и будет много отличных библиотек.

    Если вы хотите еще больше упростить взаимодействие с базой данных, такие как Париж / > стоит попробовать. Точно так же, как никто не использует более мягкий DOM в JavaScript, вам не нужно сейчас присматривать за сырым интерфейсом базы данных.

    1. устарели — они больше не поддерживаются
    2. не позволяют легко переходить на другую базу данных
    3. не поддерживает подготовленные заявления, следовательно
    4. поощрять программистов использовать конкатенацию для построения запросов, что приводит к уязвимостям внедрения SQL

    Говоря о технический Причин здесь всего несколько, крайне специфичных и редко используемых. Скорее всего, вы никогда не будете использовать их в своей жизни.
    Может быть, я слишком невежественен, но у меня никогда не было возможности использовать такие вещи, как

    • неблокирующие, асинхронные запросы
    • хранимые процедуры, возвращающие несколько результирующих наборов
    • Шифрование (SSL)
    • компрессия

    Если они вам нужны — это, без сомнения, технические причины для перехода от расширения mysql к чему-то более стильному и современному.

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

    • Дальнейшее использование этих функций в современных версиях PHP вызовет уведомления устаревшего уровня. Их просто можно отключить.
    • в отдаленном будущем они могут быть удалены из сборки PHP по умолчанию. Не так уж и страшно, так как mydsql ext будет перемещен в PECL, и каждый хостер будет рад скомпилировать с ним PHP, так как они не хотят терять клиентов, чьи сайты работали десятилетиями.
    • сильное сопротивление со стороны сообщества Stackoverflow. Каждый раз, когда вы упоминаете эти честные функции, вам говорят, что они находятся под строгим табу.
    • Будучи обычным пользователем PHP, скорее всего, ваша идея использовать эти функции подвержена ошибкам и ошибочна. Просто из-за всех этих многочисленных учебников и пособий, которые научат вас неправильному пути. Не сами функции — я должен это подчеркнуть — а то, как они используются.

    Эта последняя проблема является проблемой.
    Но, на мой взгляд, предлагаемое решение тоже не лучше.
    По-моему слишком идеалистично мечта, чтобы все эти пользователи PHP научились правильно обрабатывать запросы SQL. Скорее всего, они просто изменили бы mysql_ * на mysqli_ * механически, оставив подход тот же. Тем более, что mysqli делает использование готовых заявлений невероятно болезненным и хлопотным.
    Не говоря уже о том, что родные готовые заявления недостаточно для защиты от SQL-инъекций, и ни mysqli, ни PDO не предлагают решения.

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

    Кроме того, есть несколько ложных или несущественных причин, таких как

    • Не поддерживает хранимые процедуры (мы использовали mysql_query(«CALL my_proc»); на века)
    • Не поддерживает транзакции (как указано выше)
    • Не поддерживает множественные заявления (кому они нужны?)
    • Не в активном развитии (и что? Это влияет вы любым практическим способом?)
    • Отсутствует интерфейс OO (для его создания требуется несколько часов)
    • Не поддерживает подготовленные операторы или параметризованные запросы

    Последний интересный момент. Хотя mysql ext не поддерживает родные подготовленные заявления, они не требуются для безопасности. Мы можем легко подделать подготовленные операторы, используя заполнители, обработанные вручную (как это делает PDO):

    вуаля, все параметризовано и безопасно.

    Но хорошо, если вам не нравится красный прямоугольник в руководстве, возникает проблема выбора: mysqli или PDO?

    Ну, ответ будет следующим:

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

    Если, как и подавляющее большинство PHP-пользователей, вы используете необработанные вызовы API прямо в коде приложения (что по сути неверно) — PDO — единственный выбор, так как это расширение претендует на то, чтобы быть не просто API, а скорее полу-DAL, все еще неполным, но предлагает много важных функций, две из которых делают PDO критически отличным от mysqli:

    • в отличие от mysqli, PDO может связывать заполнители по значению, что делает динамически построенные запросы выполнимыми без нескольких экранов довольно грязного кода.
    • в отличие от mysqli, PDO всегда может вернуть результат запроса в простом обычном массиве, тогда как mysqli может сделать это только при установке mysqlnd.

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

    Тем не менее, все, кто говорит о расширениях, всегда пропускают 2 важных факта о Mysqli и PDO:

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

    Ни mysqli_ *, ни функции PDO не должны были появиться в коде приложения.
    Там должно быть слой абстракции между ними и кодом приложения, который будет выполнять всю грязную работу по связыванию, зацикливанию, обработке ошибок и т. д. внутри, делая код приложения СУХИМЫМ и чистым. Особенно для сложных случаев, таких как динамическое построение запросов.

    Так что просто переключиться на PDO или mysqli недостаточно. Нужно использовать ORM, или построитель запросов, или любой другой класс абстракции базы данных, вместо того, чтобы вызывать необработанные функции API в их коде.
    И наоборот — если у вас есть уровень абстракции между кодом приложения и MySQL API — на самом деле не имеет значения, какой двигатель используется. Вы можете использовать mysql ext до тех пор, пока он не устареет, а затем легко переписать ваш класс абстракции на другой движок, имея весь код приложения без изменений.

    Вот несколько примеров, основанных на моем класс safemysql чтобы показать, каким должен быть такой класс абстракции:

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

    Сравните это с обычными вставками PDO, когда каждое имя поля повторяется шесть-десять раз — во всех этих многочисленных именованных заполнителях, привязках и определениях запросов.

    Вы вряд ли найдете пример для PDO, чтобы справиться с таким практическим случаем.
    И это будет слишком многословно и, скорее всего, небезопасно.

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

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

    Когда используешь mysql_* функции, вы должны помнить, чтобы запустить пользовательские параметры через mysql_real_escape_string() , Если вы забыли только в одном месте или вам удалось избежать только части ввода, ваша база данных может подвергнуться атаке.

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

    Потому что (среди прочих причин) гораздо сложнее обеспечить очистку входных данных. Если вы используете параметризованные запросы, как в случае с PDO или mysqli, вы можете полностью избежать риска.

    Как пример, кто-то может использовать «enhzflep); drop table users» как имя пользователя. Старые функции позволят выполнять несколько операторов за запрос, поэтому что-то вроде этого мерзкого баггера может удалить всю таблицу.

    Если бы кто-то использовал PDO mysqli, имя пользователя в конечном итоге было бы «enhzflep); drop table users» ,

    Работа с MySQL в PHP

    PHP поддерживает работу с базой данных MySQL.
    Специальные встроенные функции для работы с MySQL позволяют просто и эффективно работать с этой СУБД: выполнять любые запросы, читать и записывать данные, обрабатывать ошибки.
    Сценарий, который подключается к БД, выполняет запрос и показывает результат, будет состоять всего из нескольких строк. Для работы с MySQL не надо ничего дополнительно устанавливать и настраивать; всё необходимое уже доступно вместе со стандартной поставкой PHP.

    Что такое mysqli?

    mysqli (MySQL Improved) — это расширение PHP, которое добавляет в язык полную поддержку баз данных MySQL. Это расширение поддерживает множество возможностей современных версий MySQL.

    Как выглядит работа с базой данных

    Типичный процесс работы с СУБД в PHP-сценарии состоит из нескольких шагов:

    1. Установить подключение к серверу СУБД, передав необходимые параметры: адрес, логин, пароль.
    2. Убедиться, что подключение прошло успешно: сервер СУБД доступен, логин и пароль верные и так далее.
    3. Сформировать правильный SQL запрос (например, на чтение данных из таблицы).
    4. Убедиться, что запрос был выполнен успешно.
    5. Получить результат от СУБД в виде массива из записей.
    6. Использовать полученные записи в своём сценарии (например, показать их в виде таблицы).

    Функция mysqli connect: соединение с MySQL

    Перед началом работы с данными внутри MySQL, нужно открыть соединение с сервером СУБД.
    В PHP это делается с помощью стандартной функции mysqli_connect() . Функция возвращает результат — ресурс соединения. Данный ресурс используется для всех следующих операций с MySQL.

    Но чтобы выполнить соединение с сервером, необходимо знать как минимум три параметра:

    Если вы следовали стандартной процедуре установки MySQL или используете OpenServer, то адресом сервера будет localhost , логином — root . При использовании OpenServer пароль для подключения — это пустая строка ‘’, а при самостоятельной установке MySQL пароль ты задавал в одном из шагов мастера установки.

    Базовый синтаксис функции mysqli_connect() :

    Проверка соединения

    Первое, что нужно сделать после соединения с СУБД — это выполнить проверку, что оно было успешным.
    Эта проверка нужна, чтобы исключить ошибку при подключении к БД. Неверные параметры подключения, неправильная настройка или высокая нагрузка заставит MySQL отвеграть новые подключения. Все эти ситуации приведут к невозможности соединения, поэтому программист должен проверить успешность подключения к серверу, прежде чем выполнять следующие действия.

    Соединение с MySQL устанавливается один раз в сценарии, а затем используется при всех запросах к БД.
    Результатом выполнения функции mysqli_connect() будет значение специального типа — ресурс.
    Если подключение к MySQL не удалось, то функция mysqli_connect() вместо ресурса вернет логическое значение типа «ложь» — false .
    Хорошей практикой будет всегда проверять значение результа выполнения этой функции и сравнивать его с ложью.

    Соединение с MySQL и проверка на ошибки:

    Функция mysqli_connect_error() просто возвращает текстовое описание последней ошибки MySQL.

    Установка кодировки

    Первым делом после установки соединения крайне желательно явно задать кодировку, которая будет использоваться при обмене данными с MySQL. Если этого не сделать, то вместо записей со значениями, написанными кириллицой, можно получить последовательность из знаков вопроса: ‘. ’.
    Вызови эту функцию сразу после успешной установки соединения: mysqli_set_charset($con, «utf8»);

    Выполнение запросов

    Установив соединение и определив кодировку мы готовы выполнить свои первые SQL-запросы. Ты уже умеешь составлять корректные SQL команды и выполнять их через консольный или визуальный интерфейс MySQL-клиента.
    Те же самые запросы можно отправлять без изменений и из php-сценария. Помогут в этом несколько встроенных функций языка.

    Два вида запросов

    Следует разделять все SQL-запросы на две группы:

    1. Чтение информации (SELECT).
    2. Модификация (UPDATE, INSERT, DELETE).

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

    Добавление записи

    Вернёмся к нашему проекту — дневнику наблюдений за погодой. Начнём практическую работу с заполнения таблиц данными. Для начала добавим хотя бы один город в таблицу cities.

    Выражение INSERT INTO используется для добавления новых записей в таблицу базы данных.

    Составим корректный SQL-запрос на вставку записи с именем города, а затем выполним его путём передачи этого запроса в функцию mysqli_query() , чтобы добавить новые данные в таблицу.

    Обратите внимание, что первым параметром для функциии mysqli_query() передаётся ресурс подключения, полученный от функции mysqli_connect() , вторым параметром следует строка с SQL-запросом.
    При запросах на изменение данных (не SELECT) результатом выполнения будет логическое значение — true или false.
    false будет означать, что запрос выполнить не удалось. Для получения строки с описанием ошибки существует функция mysqli_error($link) .

    Функция insert id: как получить идентификатор добавленной записи

    Следующим шагом будет добавление погодной записи для нового города.
    Погодные записи хранит таблица weather_log, но, чтобы сослаться на город, необходимо знать идентификатор записи из таблицы cities.
    Здесь пригодится функция mysqli_insert_id() .
    Она принимает единственный аргумент — ресурс соединения, а возвращает идентификатор последней добавленной записи.

    Теперь у нас есть всё необходимое, чтобы добавить погодную запись.
    Вот как будет выглядеть комплексный пример с подключением к MySQL и добавлением двух новых записей:

    Чтение записей

    Другая частая операция при работе с базами данных в PHP — это получение записей из таблиц (запросы типа SELECT).
    Составим SQL-запрос, который будет использовать SELECT выражение. Затем выполним этот запрос с помощью функции mysqli_query() , чтобы получить данные из таблицы.

    В этом примере показано, как вывести все существующие города из таблицы cities:

    В примере выше результат выполнения функции mysqli_query() сохранён в переменной $result .
    Важно понимать, что в этой переменной находятся не данные из таблицы, а специальный тип данных — так называемая ссылка на результаты запроса.

    Чтобы получить действительные данные, то есть записи из таблицы, следует использовать другую функцию — mysqli_fetch_array() — и передать ей единственным параметром эту самую ссылку.
    Теперь каждый вызов функции mysqli_fetch_array() будет возвращать следующую запись из всего результирующего набора записей в виде ассоциативного массива.

    Цикл while здесь используется для «прохода» по всем записям из полученного набора записей.
    Значение поля каждой записи можно узнать просто обратившись по ключу этого ассоциативного массива.

    Как получить сразу все записи в виде двумерного массива

    Иногда бывает удобно после запроса на чтение не вызывать в цикле mysqli_fetch_array для извлечения очередной записи по порядку, а получить их сразу все одним вызовом. PHP так тоже умеет. Функция mysqli_fetch_all($res, MYSQLI_ASSOC) вернёт двумерный массив со всеми записями из результата последнего запроса.
    Перепишем пример с показом существующих городов с её использованием:

    Как узнать количество записей

    Часто бывает необходимо узнать, сколько всего записей вернёт выполненный SQL запрос.
    Это может помочь при организации постраничной навигации, или просто в качестве информации.
    Узнать число записей поможет функция mysqli_num_rows() , которой следует передать ссылку на результат запроса.

    PHP 5 Функции Mysqli

    PHP MySQLi Введение

    PHP MySQLi = PHP MySQL Улучшено!

    Функции Mysqli позволяет получить доступ к серверам баз данных MySQL.

    Примечание: расширение MySQLi предназначен для работы с MySQL версии 4.1.13 или более поздней версии.

    Установка / Настройка во время выполнения

    Для функций Mysqli быть доступны, вы должны скомпилировать PHP с поддержкой расширения MySQLi.

    Расширение MySQLi была введена с PHP версии 5.0.0. Native Driver MySQL был включен в PHP версии 5.3.0.

    PHP+MySQL через ООП интерфейс


    ребят,
    mysql_fetch_assoc(): supplied argument is not a valid MySQL result resource

    13.04.2010, 21:48

    Как сделать красиво и правильно? ООП + PHP + MySQL
    В одной из функций класса производится подключение к БД. Возможно ли реализовать что-то.

    Обновление в mysql через php
    Здравствуйте! Делаю админку, из неё редактировать данные в mysql. Не могу понять где ошибка.

    Запроса через в php в mysql
    Уважаемые пользователи помогите с построением запроса через в php в mysql Необходимые таблицы на.

    Переход с mysql на mysqli в php 7

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

    На сегодня в php 7 исчезла стандартная команда для работы с БД mysql и большая часть функций, которая с ней связана. Теперь используется mysqli. Он доступен с версии php 5.3. Поэтому на 95% серверах лучше сразу программировать в новом формате под mysqli.

    Рассмотрим методы перехода с mysql на mysqli

    Подключение к БД (старое mysql):
    mysql_connect($database_host, $database_user, $database_password);
    mysql_query(«SET NAMES ‘utf8′»);
    mysql_select_db($database_name);

    Подключение к БД (новое mysqli):
    $connect = mysqli_connect($database_host, $database_user, $database_password, $database_name);
    mysqli_query($connect, «SET NAMES utf8»);

    В обоих примерах:
    $database_host — хост сервера
    $database_user — пользователь БД
    $database_password — пароль пользователя БД
    $database_name — выбранная БД

    Заметьте в новом подключении используется всего одна строка (переменная $connect), в которой сразу прописаны все данные. И в новом формате чаще всего mysql будет заменяться на mysqli.

    Рассмотрим создание таблиц:

    Старый синтаксис:
    mysql_query(«create table IF NOT EXISTS reitingpeopl (id int not null AUTO_INCREMENT, name TEXT(100000) not null, emails TEXT(100000) not null, PRIMARY KEY(id) ) DEFAULT CHARACTER SET utf8 «);

    Новый синтаксис:
    mysqli_query($connect, «create table IF NOT EXISTS reitingpeopl (id int not null AUTO_INCREMENT, name TEXT(100000) not null, emails TEXT(100000) not null, PRIMARY KEY(id) ) DEFAULT CHARACTER SET utf8 «);

    Здесь все как и раньше, только mysql_query меняется на mysqli_query и добавляется $connect для соединения с БД.

    Теперь рассмотрим циклы:

    Старый синтаксис:
    $podresult = mysql_query(«select * from reitingpeopl where «);
    while ($podrow=mysql_fetch_array($podresult))

    Новый синтаксис:
    $podresult = mysqli_query($connect, «select * from reitingpeopl where «);
    while ($podrow=mysqli_fetch_array($podresult))

    В новом синтаксисе используется mysqli_fetch_array вместо mysql_query и пишется $connect для подключения к БД.

    В принципе это основы. Приведу пару примеров, которые также могут вами использоваться:
    mysql_real_escape_string($_POST[«yourid»]) меняется на: mysqli_real_escape_string($connect, $_POST[«yourid»])
    mysql_query(«select * from reitingpeopl»); меняется на: mysqli_query($connect, «select * from reitingpeopl»);

    Еще популярные примеры команд (просто добавьте на конце i):
    mysqli_fetch_row()
    mysqli_fetch_assoc()
    mysqli_fetch_array()
    mysqli_num_rows()
    mysqli_insert_id()
    mysqli_close()

    Если что-то вы не нашли, то это можно будет легко отыскать в справочниках. В любом случае mysqli в php 7 работает намного быстрее, чем mysql, поэтому не задумываясь переходите в новый формат!

    инъекция Уязвимости PHP(устаревшего) модуля mysql против MySQLi и PDO

    stmt php (4)

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

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

    Я бы предложил рефакторинг. Период. Просто сделай это. Имейте в виду рефакторинг, и не изменяйте или не расширяйте свою кодовую базу при этом — это неприятная ловушка. Несмотря на то, что это будет какая-то работа — рефакторинг, просто начните процесс рефакторинга (разветвленный, конечно). Это будет очень удовлетворительно при завершении. Ожидайте некоторые проблемы с длинным хвостом.

    Я предполагаю, что все описанные вами функции уже завернуты, поэтому рефакторинг должен быть достаточно выполнимым. Если вещи не были завернуты .. ($ # @!), Определите способ однозначного отслеживания вызовов функций (включая контекст) по всему проекту (возможно, используя регулярные выражения в поиске их всех) и замените их новыми уникальными функциями, be-used wrapper. Сначала исследуйте это, тщательно. Через пол дня вы сможете заручиться всем своим регулярным выражением, которое вам понадобится. Поэтому сначала планируйте это, сначала исследуя свой путь.

    Заполните новые обертки текущим (старым) функциональным кодом и посмотрите, все ли работает, как было.

    Затем перейдите на mysqli и перестройте свои обертки внутри.

    Кажется, это простой, по возможности подход, избегая всех вопросов и вопросов, которые останутся в глубине вашего ума, несмотря на то, что вы пытаетесь сделать, взломав свой путь глубже вокруг обычного mysql. Мне не нужно рассказывать о преимуществах, которые принесет mysqli, вы уже знаете это. Кроме того, это просто хорошая практика каждый раз, когда на самом деле берут на себя такие проблемы раз и навсегда. Планируйте, обсудите, ответьте, попробуйте, сделайте, испытайте, заполните и победите! В довершении всего: убедитесь, что вы не можете использовать возможности расширения вашей базы кода и функциональной области при рефакторинге — у вас возникнет соблазн сделать это: просто рефакторинг. Добавьте, расширьте или улучшите позже.

    Я отвечаю за поддержание и расширение базы PHP-кода, которая началась в 2007 году и использует оригинальный модуль mysql . Все пользовательские вводятся с помощью кастинга для значений, которые, как ожидается, будут численными, mysql_real_escape_string() цитируются с использованием одинарных кавычек для строк, возможно, дополнительно фильтруются через in_array() для полей ENUM или array_intersect() для полей SET . Все строки с неограниченной строкой передаются через htmlspecialchars() или htmlentities() при выводе HTML. Если значение представляет собой внешний ключ, этот ключ сначала проверяется.
    Я считаю, что, строго следуя этим процедурам, приложение настолько же безопасно, как и против инъекций и других форм атаки. (бонусные баллы: я прав? Если нет, что мне не хватает?)

    Преобразование этого приложения в mysqli или PDO было бы довольно большой задачей (и, во избежание случайного поломки, не то, что я хотел бы автоматизировать). Итак, наконец, на мой вопрос: Существуют ли какие-либо конкретные уязвимости, которые нельзя смягчить при использовании старого модуля mysql , который требует перехода на новые модули?

    Информация о Bounty:
    Чтобы быть ясным, я надеюсь на список CVE-номеров или заявление разработчиков PHP о том, что модуль mysql исправлен против всех известных уязвимостей, таких как дата и дата. Я также предполагаю, что после использования лучших современных методов использования модуля я не предоставляю дополнительные атак. BCP уже включают экранирование данных, взятых из db, прежде чем вставлять их в новый оператор. Продолжение и повторение этого вопроса на самом деле не затрагивает вопрос.

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

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

    EDIT в ответ на справедливый комментарий YCs ниже: во избежание двусмысленности я всегда ставил все, что пользователь генерировал через подготовленный оператор, даже если он уже был сохранен в db. По возможности я избегаю повторной установки пользовательских данных, хотя, поскольку это ненадежно, поэтому системные функции зависят от автоматически генерируемых индексов.

    Справедливости ради, страницы коротки (не более 1000 строк), поэтому исправление не займет много времени на странице, и у них мало запросов, поэтому снижение производительности не заметно и, конечно же, съедено усовершенствованиями в технологиях сервера, так как я написал исходный код , Я подозреваю, что вы обнаружите, что сокращение побега и т. Д. Значительно перевешивает любой удар производительности в операциях с подготовкой, хотя вам придется проверить, является ли это критическим.

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

    Способ, которым я собираюсь изменить, — добавить соединение mysqli в файл заголовка базы данных. Все это использует новый код. Когда я нахожу время, я обновляю старый код и тестирую каждую страницу, используя заголовочный файл, у которого нет старого соединения mysql. Слишком быстро найти биты, которые вы пропустили в среде Dev, и это может быть очень хороший способ использовать время, которое иначе было бы потрачено впустую, поскольку каждая страница занимает всего несколько минут для обновления, поэтому это можно сделать во время размывания мозгов периоды.

    Заметка о заказе второго порядка BTW, поскольку это была самая распространенная уязвимость, которую я создал:

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

    Вполне возможно, что код может быть введен через вашу защиту, а затем использоваться позже. Это вряд ли будет работать, поскольку оно сильно зависит от неуклюжий db и дизайна приложения, но некоторые из самых умных людей в мире — это хакеры. Зачем облегчать их жизнь?

    Атака становится более вероятной, если ваш sql прост, и ваше приложение выполняет любой подзапрос, используя данные, ранее полученные из db. Помните, что

    поэтому, если он был извлечен и помещен в переменную PHP, которая затем используется в запросе sql, который не используется, он может вызвать проблемы так же, как если бы он никогда не был экранирован. Если вы просто используете операторы prep для всех запросов, риск уходит навсегда, хотя помните, что инструкция prep все еще хранит вредоносный код, поэтому вам все равно придется снова использовать подготовленный оператор, когда вам нужно будет использовать введенные данные.

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

    Рискуя повторения, стоит также стать очень дружелюбным к сайту OWASP, который проводит ценные обсуждения в области безопасности.

    У меня есть всего 2 возражения

    • All user input is escaped — это критическая ошибка, приводящая к инъекции второго порядка . «Все динамические данные для SQL» — это правильный подход и формулировка
    • в вашем сообщении нет идентификаторов, но я не могу поверить, что у вас нет запроса с динамическим идентификатором в вашем коде с 2007 года.

    Также есть небольшое неудобство: через пару лет (возможно, 3-4) ваш PHP начнет выдавать ошибки уровня E_DEPRECATED. Но их можно просто отключить.

    Во всяком случае, просто механический переход от одного API к другому не будет иметь особого смысла.
    Рефакторинг вашего кода обработки SQL только для использования некоторого механизма абстракции, будь то ORM, AR, QueryBuilder или любой другой технологии, которая будет стереть необработанные вызовы API из кода приложения. Это не только сделает ваш код менее раздутым, но и сделает его независимым от любой другой прихоти, которая в будущем поразит разработчиков PHP.

    Чтобы ответить на отредактированный вопрос.

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

    Итак, я сделал небольшое исследование, и единственная уязвимость, которую я обнаружил в отношении расширения mysql, также, похоже, влияет на mysqli, равно как и расширение CVE-2007-4889, которое является уязвимостью «безопасного режима» и было исправлено долгое время назад, что еще более важно, что модули mysql.so и mysqli.so в основном используют те же самые импортные товары, которые можно увидеть —

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

    Как уже упоминалось, я потратил больше времени на аудит исходного кода PHP, убедившись, что несколько вещей —

    SQL-инъекции — параметризованные SQL- запросы — лучшее решение против подобных недостатков.

    XSS (скрипты для кросс-сайтов) — используйте htmlspecialchars () для фильтрации опасных символов

    CSRF (Подделка запроса на межсайтовый запрос) — Всегда выполняйте проверку реферера в формах, чтобы убедиться, что данные получены из нужного места

    Включение файлов — убедитесь, что пользовательский ввод не может напрямую влиять на включение (require (), require_once (), include (), include_once ()) файлов

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

    Безопасность PHP на сервере

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

    Выполнять скрипты на PHP могут веб-серверы Apache, Nginx и Lighttpd. Также PHP может выполняться интерпретатором прямо из командной строки. Но поскольку PHP установлен на сервере, он может создать ряд проблем с безопасностью, поэтому его нужно применять осторожно.

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

    Как улучшить безопасность PHP?

    Все приведенные ниже советы рассчитаны на то, что PHP работает под управлением Nginx или Apache, сам интерпретатор PHP недоступен из внешней сети. А теперь, перейдем к рассмотрению того как выполняется защита php кода, сайта и сервера в целом.

    1. Знайте врага в лицо

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

    • XSS — это уязвимость в веб-приложениях, с помощью которой злоумышленники могут выполнять произвольный JavaScript код в браузере пользователей, и таким образом, украсть его данные. Возникает из-за отсутствия проверки на данных в скриптах на правильность;
    • SQL инъекция — это уязвимость в коде работы с базой данных. Если пользовательский ввод неверно фильтруется скриптом, и используется для формирования запроса к базе данных, то злоумышленники могут выполнить любые запросы к базе данных. Для предотвращения такой проблемы рекомендуется фильтровать данные функцией mysql_real_escape_string() перед отправкой запроса;
    • Загрузка файлов — позволяет посетителю загружать файлы на ваш сервер. Загрузив определенный тип файлов, пользователи могут получить доступ к системе или даже украсть информацию из базы данных, поэтому нужно следить чтобы можно было загружать только картинки;
    • Удаленное выполнение — злоумышленник может удаленно выполнять php файлы, которые есть на сервере, поэтому вместе с возможностью загрузки PHP файлов это представляет серьезную опасность;
    • Eval() — позволяет выполнить код PHP, переданный в строке, часто используется злоумышленниками, чтобы скрыть свой код на вашем сервере;
    • CSRF атака — позволяет заставить пользователя выполнить нежелательные действия в веб-приложениях. Если пользователь является администратором, это может поставить под угрозу все приложение.

    2. Используйте только необходимые модули

    Чтобы посмотреть все скомпилированные модули PHP выполните команду:

    Рекомендуется использовать только самые необходимые модули, чтобы увеличить безопасность. Например, вы можете отключить модуль sqlite. Для этого можно удалить его конфигурационный файл в /etc/php5/conf.d/. Но для полного удаления нужно пересобрать PHP без этого модуля.

    3. Избегайте утечек информации

    В конфигурационном файле php.ini есть строчка:

    Если установлено значение On, то PHP будет отправлять версию PHP в ответ на все запросы в заголовке X-Powered-By. Также рекомендуется скрыть версию Apache и другую информацию. Защита php от взлома, это не только аккуратное программирование, но и сокрытие информации о системе.

    4. Отключите динамические расширения

    PHP поддерживает динамическую загрузку расширений. По умолчанию загружаются все расширения, конфигурационные файлы которых есть в /etc/php/conf.d/. Также загружаются модули, которые указаны директивой extension в основном конфиге php.ini. Мы можете удалить ненужное.

    5. Вывод ошибок

    Сообщения об ошибках содержат много информации, не позволяйте их смотреть всем пользователям сайта. Приведите директиву display_errors к такому виду:

    Убедитесь, что вы сохраняете все ошибки в лог файл:

    log_errors = On
    error_log = /var/log/httpd/php_scripts_error.log

    6. Запретите загрузку файлов

    Если загрузка файлов не нужна, запретите ее:

    Но если такая функция необходима, то лучше ограничить размер файла:

    file_uploads = On
    upload_max_filesize = 1M

    Пользователи смогут загружать файлы размером не более 1 мегабайт, так безопасность в php будет больше.

    6. Отключите удаленное выполнение кода

    Если параметр allow_url_fopen включен, php может использовать такие файловые функции, как file_get_contents. С помощью нее скрипт может загружать файлы из удаленных серверов. Программисты часто забывают выполнить надлежащую фильтрацию данных, и тем самым открывают уязвимость. Для отключения измените директиву:

    Также рекомендуется отключить allow_url_include:

    7. Включите безопасный режим SQL

    В безопасном режиме SQL, интерпретатор игнорирует все аргументы, передаваемые в функции mysql_connect и mysql_pcconnect. Но в таком режиме будут работать не все скрипты, например, не будет работать WordPress, так что используйте аккуратно. Для включения добавьте директиву:

    Также рекомендуется отключить функцию magic_quotes_gpc, вместо нее лучше использовать mysql_escape_string:

    9. Контролируйте размер POST

    Метод POST используется, когда браузер хочет передать веб-серверу определенное количество данных как часть запроса, например, при загрузке файла. Злоумышленники могут использовать большие запросы, чтобы истратить ресурсы сервера. Поэтому размер лучше ограничить:

    10. Контролируйте ресурсы

    Вы можете указать максимальное время выполнения для каждого скрипта, максимальное количество памяти и максимальное время чтения данных, это увеличит безопасность сайта php в плане DOS атак:

    max_execution_time = 30
    max_input_time = 30
    memory_limit = 40M

    11. Отключите опасные функции

    PHP содержит множество функций, которые могут использоваться для взлома сервера, например, те, которые позволяют выполнять команды оболочки. Чтобы отключить, достаточно их перечислить в директиве disable_functions:

    12. Настройте Fastcgi для лучшей безопасности

    PHP может работать через FastCGI, это уменьшает использование памяти вашего веб-сервера. Нужно включить директиву force_redirect чтобы предотвратить прямое выполнение php скриптов из строки запроса, например, cgi-bin/php/hackerdir/backdoor.php. Для этого добавьте:

    13. UID и GID интерпретатора PHP

    Если вы используете внешний FastCGI сервер, то нужно чтобы он был запущен не от пользователя root. Запускайте php от имени непривелигированного пользователя. Как вы знаете, у PHP есть функции, которые позволяют выполнять команды оболочки. Очень небезопасно, если они будут выполняться от суперпользователя.

    14. Ограничение доступа к файловой системе

    Директива open_basedir позволяет установить каталог, в котором php может получить доступ к файлам с помощью таких функций, как fopen, file_get_contents и т д. Если файл находится вне этой директории PHP откажется его открывать. Вы даже не сможете использовать символические ссылки.

    15. Путь для хранения сессий

    Нужна не только защита php сайта, чтобы скрипты не смогли причинить вред системе, но и чтобы пользователи не могли получить доступ к файлам php. Сессии в php позволяют сохранить определенную информацию между обращениями пользователя. Путь, где будет храниться эта информация указан в файле /etc/php/php.ini. Убедитесь, что этот путь находится вне /var/www/ и недоступен для чтения или записи для других пользователей системы.

    16. Держите программное обеспечение в актуальном состоянии

    Все программы могут содержать различные уязвимости, поэтому важно выполнять регулярное обновление системы, чтобы вовремя применить все патчи безопасности. Нужно обновлять не только PHP, а весь программный стек, в том числе Apache.

    17. Используйте SELinux

    SELinux — это система безопасности, используемая по умолчанию в RedHat. Ее можно использовать для предотвращения несанкционированного доступа к файлам и ресурсам. Например, вы можете установить политики безопасности для веб-сервера Apache или отдельного сервера PHP. Это тоже отличная защита PHP и не только.

    18. Установите mod_security

    Это модуль Apache для обнаружения и предотвращения в веб-приложения. Он может защитить php и ваше приложение от XSS и SQL-Inj атак. Например, чтобы не позволять открывать файлы в /etc/ после установки модуля добавьте в конфигурационный файл Apache:

    А для предотвращения SQL инъекций:

    SecFilter «delete[[:space:]]+from»
    SecFilter «select.+from»

    19. Просматривайте журналы

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

    tail -f /var/log/httpd/error_log
    $ tail -f /var/log/httpd/php_scripts_error.log

    Выводы

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

    На завершение лекция про безопасность написания скриптов в PHP:

    Мастер Йода рекомендует:  Программирование Web-клиента на языке Python
    Добавить комментарий