Уязвимости 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, прежде чем вставлять их в новый оператор. Продолжение и повторение этого вопроса на самом деле не затрагивает вопрос.

Ответ 1

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

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

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

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

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

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

Ответ 2

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

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

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

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

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

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

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

Ответ 3

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

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

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

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

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

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

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

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

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

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

' OR 1=1 gets converted to
\' OR 1=1 by mysql_real_escape_string but is stored as 
' OR 1=1 in the db 

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

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

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

Ответ 4

Хорошо, поэтому я сделал небольшое исследование, и единственная уязвимость, которую Ive обнаружила в отношении расширения mysql, также, похоже, влияет на mysqli, равно как и расширение CVE-2007-4889  которая является уязвимостью "безопасного режима" и была исправлена ​​давно Более того, модули mysql.so и mysqli.so разделяют в основном те же самые импортные данные, что и их можно увидеть -

/usr/lib/php5/20090626/mysql.so:

 0x0000000000000001 (NEEDED)             Shared library: [libmysqlclient.so.18]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x000000000000000e (SONAME)             Library soname: [mysqli.so]

/usr/lib/php5/20090626/mysqli.so:

 0x0000000000000001 (NEEDED)             Shared library: [libmysqlclient.so.18]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x000000000000000e (SONAME)             Library soname: [mysql.so]

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

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

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

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

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

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

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