Сеть WordPress-сайтов наркологической клиники «От запоя»
Наркологическая клиника (бренд «Станция здоровья», Нижегородская обл.; сеть сайтов «От запоя») · Медицина / наркология (вывод из запоя, лечение алкоголизма и наркомании)
Сеть сайтов наркологической клиники: аудит, оценка безопасности и 22 доработки — всё на живом сайте, без тестовой копии и без права обновлять компоненты.
- PHP
- WordPress
- Elementor
- MySQL
- JavaScript
- CSS/SCSS
- WP-CLI
- Nginx
- WPForms
- Contact Form 7
- TablePress
- Redux Framework
- WooCommerce
- Slider Revolution
- Max Mega Menu
- Playwright
В цифрах
- 22
- пунктов ТЗ обработано (доработки на двух сайтах)
- 7
- пунктов безопасности (S1–S7) с приоритизацией и митигейтами без обновления
- CVE-2025-62047, CVSS 9.9
- критическая дыра (Arbitrary File Upload, уровень Subscriber) в case-addons 1.2.0 — выявлена и доказана
- 2 + 2
- два рабочих WordPress-сайта (отдельные БД, не Multisite) + два домена-301-редиректа
- 1223
- замены доменных ссылок при тиражировании на dzerzhinsk (wp search-replace, п.19)
- 5
- параллельных web-research агентов в фазе исследования стека
Ключевое
- Нашёл в установленном расширении критическую уязвимость 9.9 из 10: пользователь с минимальными правами мог загрузить на сервер любой файл и получить контроль над сайтами.
- Уязвимость доказана по официальным базам, а не по выводу сканера; ложные срабатывания сканера отсеял отдельно.
- Собрал план устранения из семи пунктов с оценкой сложности каждого — чтобы владелец выбирал очерёдность сам, не нарушая свой запрет на обновления.
- Весь свой код положил в одно место, переживающее обновления темы, вместо правок в саму тему, как делали до меня.
- Перенёс сделанное на второй сайт сети: у него отдельная база и другой движок форм, потребовалось 1223 замены ссылок.
Задача
У сети сайтов наркологической клиники накопился список из 22 доработок: навигация, формы заявок, прайс, поведение на телефонах, переделка первого экрана.
Сложность была не в самих правках, а в условиях. Сайты собраны на купленной готовой теме, история изменений не ведётся, тестовой копии нет, а обновлять компоненты владелец запретил — политика проекта. Любая правка идёт сразу на живой сайт, который принимает обращения людей.
Что сделано
- Начал с разведки, ничего не меняя: из чего собраны сайты, где физически лежит содержимое страниц, какие расширения установлены и что о них известно в базах уязвимостей. Каждый вывод — с доказательством: файл и строка, запрос к базе или ответ сервера с датой.
- Обнаружил в одном из установленных расширений критическую уязвимость: зарегистрированный пользователь с минимальными правами мог загрузить на сервер произвольный файл — то есть получить контроль над сетью сайтов клиники. Проверил по официальным базам, а не по выводу сканера, и отдельно отсеял ложные срабатывания.
- Собрал план устранения из семи пунктов с оценкой сложности каждого — так, чтобы владелец мог выбрать очерёдность сам и не нарушить собственный запрет на обновления.
- Обработал 22 пункта задания поэтапно. Перед каждым — резервная копия базы и файлов, к каждому — заранее описанный откат.
- Весь свой код положил в одно место, которое переживает обновления темы, вместо правок в саму тему, как делали до меня. Любую доработку можно отключить одним движением.
- Перенёс сделанное на второй сайт сети. Копированием это не решалось: отдельная база, другой движок форм — потребовалось 1223 замены ссылок.
Итог
Было
- Правки шли прямо в купленную тему; ни истории изменений, ни тестовой копии
- В установленных расширениях — незакрытая критическая уязвимость, обновления запрещены политикой
- Второй сайт сети правился отдельно и вручную
Стало
- Весь код в одном месте, переживающем обновления темы; каждая правка обратима
- Уязвимость найдена и доказана, план устранения передан владельцу
- Сделанное перенесено на второй сайт, различия движков учтены
Главная находка — критическая уязвимость в расширении темы, 9.9 балла из 10 по международной шкале: пользователь с минимальными правами мог загрузить на сервер произвольный файл и получить контроль над сетью сайтов клиники. Дыра найдена и доказана до того, как ею воспользовались; владелец получил план устранения из семи пунктов с оценкой сложности каждого.
Все 22 пункта задания обработаны, каждый — с резервной копией и готовым откатом; оба сайта сети работают. Три пункта ждут материалов от заказчика: фотографию врача, изображения вместо заглушек и цифры для блока преимуществ.
Технические детали
Решение и подход
- CSS/PHP вне темы через mu-plugin. План изначально предлагал дочернюю тему
medigo-child, но по решению заказчика выбран mu-pluginotz-custom.php— переживает обновления Medigo и не несёт риска сброса опций темы дочерней темой. В репозитории дочерней темы нет — подтверждает выбранный механизм (источник:sites/./themes/,docs/handoff.md). - Контент в БД, а не в файлах. Ключевая находка аудита: шапка/подвал — не Theme Builder и не хардкод, а CPT темы
pxl-template, назначаемые опциями Redux (header_layout=3530,footer_layout=97); меню рендерит виджет темыpxl_menu, а не Max Mega Menu (это изменило способ правок навигации). Большинство задач — правки контента/настроек в БД на проде. - Прайс-лист переписан с сохранением единого источника данных: цены остаются в TablePress (заказчик правит привычно), а вывод — современные строки-карточки «услуга + цена-пилюля» через собственный шорткод, парсящий таблицу; DataTables отключён.
- Hero первого экрана перерисован вручную (светлый дизайн), с настоящим тегом
<h1>(закрывает и SEO-пункт H1/H2), аккуратной интеграцией с прозрачной overlay-шапкой темы (position:absolute) и полным набором адаптивных брейкпоинтов. - Прод-дисциплина: фронт — nginx с микрокэшем (не LiteSpeed на edge); после правок
_elementor_dataобязателенwp elementor flush-css; проверка через cache-buster и Playwright; SSH с учётом гео-блокировки порта 22 и троттлинга парольного входа (укрупнение батчей).
Стек и обоснование
WordPress + Elementor + тема Medigo/case-addons — унаследованный стек (выбор сделан до проекта). MySQL 8.0 (Percona), PHP 8.2, WP-CLI 2.8.1, фронт nginx/1.30 с микрокэшем. Формы: WPForms (главный) и Contact Form 7 (dzerzhinsk) — разные движки, правки переносились раздельно. Прайс — TablePress. Кастом — PHP/CSS в mu-plugin (без сборочного тулинга: ни package.json/composer.json для кастома, ни CI, ни тестов — фронт собирается Elementor'ом). Визуальная регрессия — Playwright (headless Chromium). Выбор инструментов продиктован запретом на обновления и отсутствием staging: решения подбирались совместимыми с текущими (часто устаревшими) версиями и максимально обратимыми.
Инженерные вызовы
- Прод без сети и без отката-by-design: нет git и staging — компенсировано бэкапами БД/файлов перед каждой сессией, снимками
_elementor_dataперед патчем, точечными обратимыми правками и cache-flush-дисциплиной. - Контент в БД, а не в коде: правки приходилось локализовать в Elementor JSON и опциях Redux/плагинов, опровергая ошибочные исходные предположения (логотип, расположение копирайта, рендер меню темой
pxl_menu, а не Max Mega Menu). - Две инсталляции с раздельными БД и разными движками форм — тиражирование шаблонов/контента и search-replace ссылок без авто-синхронизации.
- Юридический контур РФ: наркология подпадает под ФЗ-38 ст.24 (обязательный дисклеймер «Имеются противопоказания…», раскрытие лицензии, запрет гарантий излечения и отзывов о выздоровлении; штраф юрлицу) и 152-ФЗ по ПДн пациентов из форм — это влияло на весь контент.
Безопасность (ключевая компетенция)
Отдельно оформленная экспертиза, выделенная заказчику в коммерческое предложение доп. работ (docs/reports/2026-06-18-security-additional-works.md):
- Выявлены и доказаны критические уязвимости активного стека:
case-addons 1.2.0— CVE-2025-62047, CVSS 9.9 (Arbitrary File Upload уровнем Subscriber ≈ RCE на прод-сети клиники, bundled-плагин темы без авто-апдейта);Slider Revolution 6.7.34— CVE-2025-9217 LFI (чтениеwp-config.phpс доступами к БД) +2 CVE; XSS вLiteSpeed Cache 7.7на dzerzhinsk; рассинхрон Elementor Pro 3.27.4 ↔ core 3.34.1; EOL PHP 8.2 (31.12.2026). Каждый вывод перепроверен по первоисточникам (NVD/Patchstack/WPScan/вендор) с датами; отмечены ложные срабатывания сканеров (WooCommerce 10.4.4, woo-variation-swatches). - Приоритизация и митигейты без обновления: план S1–S7 со «сложностью» под расчёт стоимости, экономикой WAF (платный WAF Timeweb — клиент не подключает), снижением attack surface (удаление неиспользуемых WooCommerce/Slider Revolution), компенсациями (отключение открытой регистрации, аудит ролей Contributor+, 2FA).
- Ответственное обращение с доступом и данными: аудит сервера — строго read-only; ПДн пациентов (
wp_wpforms_entries) не выгружались и не попадали в отчёты (152-ФЗ); секреты (SSH-доступы вdocs/credentials.md) не извлекались и не публиковались; предусмотрена ротация доступов после работ.
Услуги в проекте
- аудит
- аудит безопасности
- доработка существующего
- прод-операции (SSH/WP-CLI)
- SEO
- 152-ФЗ/ПДн
- контент
- юридическое соответствие (ФЗ-38)