Критические уязвимости PHP: обновление Docker-образа и автоматический деплой

7 мин чтения 11 просм. 11 просм. октябрь 25, 2026
Критические уязвимости PHP: обновление Docker-образа и автоматический деплой

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

И вот тут начинается самое интересное: проблема может быть не в твоём коде, не в Laravel и даже не в Composer-зависимостях. Уязвимым может оказаться сам PHP runtime.

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

Что произошло?

21 октября 2026 года были опубликованы обновления безопасности PHP, устраняющие две критические уязвимости удалённого выполнения кода — Remote Code Execution (RCE).

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

Речь идёт о двух уязвимостях:

- CVE-2026-109618 — проблема, связанная с обработкой исчерпания памяти и внутренними структурами PHP.
- CVE-2026-109619 — проблема, связанная с использованием устаревшего внутреннего состояния и обращением к памяти, которая уже не должна использоваться.

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

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

Проверить информацию можно в официальном разделе безопасности PHP и в базе CVE.

В каких версиях PHP исправили уязвимости?

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

Ветка PHP

Версия с исправлениями

PHP 8.2

8.2.35

PHP 8.3

8.3.36

PHP 8.4

8.4.27

PHP 8.5

8.5.12

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

Также важно учитывать жизненный цикл PHP: старые неподдерживаемые ветки могут не получать исправления от самого проекта PHP.

Что будет, если не обновить PHP?

Представим обычное веб-приложение. Пользователь отправляет HTTP-запрос, Nginx передаёт его PHP-FPM, а PHP обрабатывает запрос и запускает код приложения.

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

При успешной атаке возможны следующие последствия:

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

Масштаб ущерба зависит от прав процесса, настроек контейнера, доступных секретов и изоляции инфраструктуры.

Отдельно стоит отметить: Nginx перед PHP-FPM сам по себе не защищает от уязвимости в PHP. Если запросы обрабатываются уязвимым интерпретатором, наличие reverse proxy не устраняет проблему.

Поэтому своевременное обновление runtime — такая же часть поддержки приложения, как обновление библиотек и исправление ошибок в собственном коде.

Как я обновила PHP в своём Docker-проекте

Мой проект работает в Docker Compose. В Dockerfile используется многоэтапная сборка — multi-stage build.

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

1. Разобралась в Dockerfile

В проекте используются четыре стадии сборки:

- `assets` — сборка фронтенда на Node.js;
- `builder` — установка PHP-расширений и Composer-зависимостей;
- `production` — финальный образ приложения;
- `development` — образ для разработки, наследующий production и дополнительно устанавливающий Xdebug.

Для PHP использовался базовый образ:

FROM php:8.4-fpm AS builder

И ещё один:

FROM php:8.4-fpm AS production

Здесь важно не пропустить вторую строку. Обновить только `builder` недостаточно, если финальный production-образ продолжает использовать старую версию PHP.

Стадия `development` наследуется от `production`, поэтому отдельный базовый PHP-образ для неё не требуется.

2. Обновила базовый образ PHP

Для ветки PHP 8.4 исправленная версия — 8.4.27.

Я заменила обе строки в Dockerfile:

FROM php:8.4.27-fpm AS builder
FROM php:8.4.27-fpm AS production

Таким образом, исправленная версия PHP используется и на этапе сборки зависимостей, и в финальном production-образе.

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

Разумеется, после изменения базового образа важно проверить успешность сборки и совместимость приложения с обновлённым окружением.

3. А дальше за меня работает CI/CD

Вот здесь начинается моя любимая часть истории.

Мне не пришлось вручную заходить на сервер, выполнять `docker compose build`, собирать образ и заниматься его доставкой в production. В проекте уже настроен автоматизированный процесс с использованием GitHub Actions, приватного Docker Hub и Ansible.

Процесс выглядит следующим образом:

1. Я изменяю Dockerfile и отправляю изменения в ветку `master`.
2. GitHub Actions запускает сборку Docker-образа в соответствии с настроенным workflow.
3. Собранный образ публикуется в приватный Docker Hub.** Образ приложения хранится в закрытом registry, а не в публичном репозитории.
4. Ansible доставляет обновление на production. Он подтягивает опубликованный образ и выполняет предусмотренные конфигурацией действия по развёртыванию приложения.

В итоге путь от изменения Dockerfile до обновления приложения на сервере автоматизирован.

Мне не нужно помнить последовательность команд для ручного деплоя или каждый раз самостоятельно собирать образ на production-сервере. Я вношу изменение в репозиторий, а настроенный процесс CI/CD выполняет свою работу.

Конечно, автоматизация не отменяет проверки: после обновления необходимо убедиться, что на production действительно запущена исправленная версия PHP, а приложение работает корректно.

Но именно в такие моменты особенно хорошо видно, насколько полезна инфраструктура, которую однажды правильно настроили.

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

4. Проверила результат

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

Для этого можно выполнить:

docker compose exec php php -v

Здесь `php` — пример имени сервиса из Compose-файла.

В выводе должна отображаться исправленная версия PHP или более новая версия той же ветки, содержащая необходимые патчи.

Дополнительно стоит проверить расширения:

docker compose exec php php -m

В моём проекте используются `pdo_mysql`, `pdo_pgsql`, `intl`, `zip`, `redis`, `opcache` и другие расширения. После обновления важно убедиться, что все необходимые модули доступны.

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

Достаточно ли обновить только PHP?

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

В проекте остаются другие компоненты:

- Nginx — отдельный компонент со своими обновлениями безопасности.
- Node.js — используется для сборки фронтенда.
- Системные библиотеки — устанавливаются через пакетный менеджер и также могут содержать уязвимости.
- Composer-зависимости — сторонние PHP-пакеты необходимо проверять отдельно.

Для проверки Composer-зависимостей можно использовать:

composer audit

Для сканирования Docker-образов на известные уязвимости подойдёт Trivy.

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

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

Выводы

Эта история напомнила мне несколько вещей.

Во-первых, безопасность приложения зависит не только от кода, который мы пишем. Базовые Docker-образы, интерпретатор, системные библиотеки и сторонние зависимости тоже требуют внимания.

Во-вторых, multi-stage Dockerfile нужно читать внимательно. Обновить одну строку в одной стадии не всегда достаточно: важно понимать, какой образ в итоге запускается на production.

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

И наконец, я ещё раз убедилась, что хорошо настроенный CI/CD — это не просто удобство, а реальная помощь в работе с инфраструктурой.

Я меняю Dockerfile, отправляю изменения в `master`, GitHub Actions собирает образ, приватный Docker Hub хранит его, а Ansible доставляет обновление на production. Никакой ручной сборки на сервере.

Недостаточно просто знать, какую версию PHP нужно установить. Хорошо ещё настроить процессы так, чтобы необходимые изменения можно было безопасно и предсказуемо доставлять до production.

Backend-разработка — это не только контроллеры, SQL-запросы и исправление багов. Это ещё и понимание того, как приложение собирается, запускается, обновляется и защищается.

А когда в нужный момент инфраструктура работает так, как задумано, можно спокойно сказать: горжусь собой :)

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

Поделиться: