Когда «website hacked» — это инцидент, а не «сейчас почистим и забудем»
Взлом сайта почти никогда не ограничивается одним «левым файлом в uploads». Обычно атакующий успевает закрепиться (бекдор), расширить доступ (украсть ключи/токены), настроить повторный вход и, по возможности, замести следы. Поэтому правильная реакция — это не только malware cleanup, но и дисциплинированный incident response: зафиксировать состояние, локализовать ущерб, восстановить сервис и закрыть первопричину.
Ниже — практичный план для админов/DevOps/вебмастеров, который можно выполнять в одиночку. Я исхожу из типового стека Linux + Nginx/Apache + PHP/Node/Python, база данных и CMS.
Цель: не «сделать, чтобы открылось», а вернуть сайт в управляемое состояние так, чтобы атакующий не зашёл повторно тем же способом.
Фаза 0. Стабилизация: остановить развитие инцидента
Первое правило: не паниковать и не начинать хаотично удалять файлы. Ваша задача — остановить дальнейший ущерб и не уничтожить улики, которые помогут понять вектор атаки.
1) Изоляция (isolation): ограничиваем радиус поражения
Изоляция нужна, чтобы прекратить утечку данных, рассылку спама, установку новых бэкдоров и вредоносные редиректы. Варианты по степени жёсткости:
Закрыть публичный доступ к сайту: временная заглушка 503, доступ только с вашего IP/VPN.
Ограничить исходящие соединения на уровне фаервола, если видите подозрительную активность (эксфильтрация, ботнет).
Остановить сервисы (php-fpm, node, очереди), если заражение активно меняет файлы или рассылает запросы.
Сделать снапшот/клон диска (если инфраструктура позволяет) и разбирать уже копию.
Если сайт критичный, иногда делают «мягкую изоляцию»: оставить чтение, но запретить запись (например, отключить загрузки, временно убрать права записи на каталоги). Но если атакующий уже имеет доступ к панели/SSH, рассчитывать на это опасно.
2) Сохраняем артефакты (до «чистки»)
Минимальный набор, который стоит сохранить до любых действий:
логи веб-сервера (access/error) и логи приложения;
логи аутентификации и sudo (например, auth.log / secure, journalctl);
список процессов и сетевых соединений;
копию webroot и конфигов (хотя бы архивом);
сведения о пользователях/ключах, которые могли быть затронуты.
Это не «цифровая криминалистика», а практичная страховка: 10–15 минут фиксации часто экономят часы догадок позже.
Фаза 1. Быстрая оценка ущерба: что именно произошло
1) Признаки компрометации
Типовые сигналы:
редиректы на сторонние сайты, подмена выдачи поисковикам;
неожиданные cron-задачи, новые systemd units, «левые» процессы;
подозрительные файлы в webroot:
.phtml,.phpв местах, где их не должно быть, «картинки» с PHP-кодом;всплеск исходящего трафика/SMTP/HTTP;
новые админы в CMS, изменения в шаблонах, вставки
eval/base64_decodeи подобного;утечки секретов из репозитория/переменных окружения.
2) Log review: с чего начать разбор логов
Задача log review — найти «первую точку входа» и временную шкалу. Начните с вопросов:
когда начались изменения (первые странные записи/ошибки/редиректы);
какие URL дергали перед заражением (подозрительные POST, загрузки файлов, вызовы админки);
с каких IP шли запросы и совпадают ли они с попытками логина по SSH/панели;
что происходило на уровне ОС в это время (sudo, новые пользователи, запуск бинарников).
Примеры команд для первичного просмотра (подстройте пути под вашу систему):
sudo tail -n 200 /var/log/nginx/error.log
sudo tail -n 200 /var/log/nginx/access.log
sudo grep " POST " /var/log/nginx/access.log | tail -n 50
sudo grep "wp-login.php" /var/log/nginx/access.log | tail -n 50
sudo grep "\.php" /var/log/nginx/access.log | tail -n 50
Если логи в journald:
sudo journalctl -u nginx --since "2025-12-28 00:00" --no-pager | tail -n 200
sudo journalctl --since "2025-12-28 00:00" -t sshd --no-pager | tail -n 200
Для SSH-аудита (Debian/Ubuntu):
sudo grep -E "Accepted|Failed|Invalid user" /var/log/auth.log | tail -n 200
Если вы видите признаки того, что атакующий получил root, считайте систему недоверенной. Тогда «чистка на месте» часто хуже, чем переустановка и восстановление из проверенных бэкапов.
Если вы восстанавливаете сервис на новом сервере или хотите быстро развернуть «чистое» окружение для возврата в прод, практичнее делать это на отдельном VDS: проще изолировать инцидент, контролировать доступ и безопасно перенести только проверенные данные.

Фаза 2. Containment: остановить повторный вход
1) Rotate secrets: меняем всё, что могло утечь
Rotate secrets — один из самых недооценённых шагов. Даже если вы удалили вредоносный файл, атакующий может зайти повторно «по ключам», которые он успел украсть.
Менять лучше по приоритету:
Доступы админов: SSH-ключи, пароли, 2FA, доступы к панели управления.
База данных: пароль пользователя БД, отдельные учетные записи (если есть).
Секреты приложения:
APP_KEY, JWT/HMAC ключи, ключи шифрования, salts.Интеграции: SMTP, платежные шлюзы, webhook secret, API tokens.
CI/CD: токены деплоя, ключи доступа к репозиторию/registry.
Фиксируйте, что и когда вы ротировали: какие токены отозваны, какие сессии должны стать недействительными. Если у приложения есть механизм принудительного разлогина — включайте.
2) Временно ужесточаем поверхность атаки
Пока вы разбираетесь с инцидентом, имеет смысл временно включить ограничения:
закрыть админ-панели по IP allowlist;
отключить неиспользуемые эндпоинты (например, XML-RPC, если он вам не нужен);
перевести upload-директории в режим «без исполнения» (запрет PHP/CGI);
проверить права на файлы: веб-серверу не нужен доступ на запись во весь проект.
Фаза 3. Malware cleanup: чистим так, чтобы не оставить «семена»
1) Не лечим симптомы: определяем источник
Частая ошибка — удалить найденный бэкдор и успокоиться. Если первопричина — уязвимый плагин, слабый пароль, утёкший ключ или возможность записи в webroot, бэкдор вернётся.
Поэтому malware cleanup делайте параллельно с поиском ответа на вопрос «как зашли».
2) Инвентаризация изменений: что появилось и что менялось
Если у вас есть эталон (репозиторий, релизный архив), сравнивайте с ним. Если эталона нет — хотя бы найдите свежие изменения по времени:
sudo find /var/www -type f -mtime -7 -print | head -n 200
sudo find /var/www -type f -name "*.php" -mtime -7 -print | head -n 200
Полезно искать типовые маркеры веб-шеллов (помните о ложных срабатываниях):
sudo grep -R --line-number "base64_decode" /var/www | head -n 200
sudo grep -R --line-number "eval(" /var/www | head -n 200
sudo grep -R --line-number "gzinflate" /var/www | head -n 200
Проверьте автозапуски:
sudo crontab -l
sudo ls -la /etc/cron.*
sudo systemctl list-unit-files --type=service | grep enabled
И необычные слушающие порты/процессы:
sudo ss -lntup
sudo ps auxf | head -n 80
3) Тактика «чистого выката» вместо ручного удаления
На практике самый надёжный способ очистки webroot — не выковыривать вредоносные фрагменты, а:
развернуть чистую копию приложения из доверенного источника (репозиторий/артефакты сборки);
перенести только проверенные пользовательские данные (uploads) после проверки и запрета исполнения;
переинициализировать конфиги и секреты;
обновить ядро/плагины/зависимости до безопасных версий.
Если это CMS, часто быстрее поднять чистую версию той же ветки, поставить плагины из официальных источников и импортировать контент, чем «лечить» десятки изменённых файлов.
Фаза 4. Восстановление (recovery) и возврат в прод
1) Recovery plan: что должно быть готово заранее
Recovery plan — это не «красивый документ», а короткий чек-лист: где бэкапы, как поднять окружение, где хранятся секреты, как переключить DNS/балансировщик, как проверить работоспособность. Если плана нет — составьте его по факту инцидента и сохраните как артефакт.
Минимальный план восстановления включает:
точку восстановления (какой бэкап считаем «чистым»);
RPO/RTO (сколько данных можно потерять и сколько можно лежать);
порядок развёртывания: ОС → пакеты → конфиги → приложение → БД → кеши → воркеры;
проверки после восстановления (healthchecks, авторизация, платежи, почта, загрузки).
2) Восстанавливаем из бэкапа: важные нюансы
Бэкап «до атаки» не всегда чистый: атакующий мог сидеть скрытно. Если есть возможность, проверьте несколько точек во времени: сравните логи и изменения файлов.
После восстановления обязательно:
применить патчи и обновления, закрывающие вектор атаки;
включить/усилить правила на уровне веб-сервера (аккуратно, чтобы не положить легитимный трафик);
проверить права на каталоги, где разрешена запись;
убедиться, что секреты уже ротированы, а старые токены отозваны.
Если восстановление связано с переносом на новую площадку, полезно держать план миграции без простоя. В помощь — чек-лист из статьи про миграцию сайта без даунтайма.
После инцидента почти всегда полезно перепроверить TLS-настройки и перевыпустить сертификаты при необходимости. Если вы меняете доменные привязки или хотите быстрее закрыть вопрос с доверием браузеров, посмотрите наши SSL-сертификаты GlobalSign.

3) Проверки «перед открытием ворот»
Пройдитесь по контрольному списку:
главные страницы и формы работают, нет неожиданных редиректов;
админка доступна только ожидаемым способом (IP/VPN/2FA);
веб-сервер не исполняет код из upload-директорий;
в логах нет повторяющихся подозрительных запросов к уязвимому endpoint;
нет неожиданных исходящих соединений/SMTP-активности;
мониторинг и алерты включены хотя бы на 5xx, всплеск трафика, дисковое место.
Фаза 5. Post-incident: закрепляем результат, чтобы не повторилось
1) Разбор причин (root cause) и изменения процесса
Завершение инцидента — не момент, когда сайт снова отвечает, а момент, когда вы можете уверенно объяснить:
какой был вектор входа (уязвимость, слабый пароль, утёкший ключ, RCE в плагине);
какие данные могли быть затронуты;
какие меры внедрены, чтобы этот класс атаки не повторился.
Если причина не установлена, считайте риск повторной компрометации высоким и усиливайте наблюдаемость: логирование, алерты, контроль целостности.
2) Базовые меры, которые реально снижают шанс повторения
Разделение прав: web-пользователь не должен иметь лишних прав на запись и тем более на конфиги с секретами.
Секреты вне репозитория и регулярный rotate secrets по расписанию.
Обновления: ядро, плагины, зависимости — с понятным окном обслуживания.
Логи: ротация и ретеншн, чтобы log review был возможен через неделю, а не только «пока файлы не перетёрлись».
Бэкапы: проверенные восстановлением, с раздельным хранением и контролем доступа.
Сегментация: не держать «всё на одном сервере» без нужды (БД отдельно, приватные сети, минимальные открытые порты).
Если вы используете общий хостинг, отдельное внимание уделите настройкам PHP и кэша: они не «лечат» взлом, но помогают стабильности после восстановления. По производительности и конфигурации окружения пригодится материал про OPcache и Brotli на хостинге.
Короткий чек-лист на случай «прямо сейчас»
Изолируйте узел (isolation): ограничьте доступ, остановите подозрительные сервисы.
Сохраните логи/процессы/сетевые соединения и копию webroot до чистки.
Начните log review: найдите временную шкалу и возможную точку входа.
Rotate secrets: SSH, БД,
APP_KEY, токены интеграций, CI/CD.Malware cleanup через «чистый выкат» из доверенного источника.
Восстановите по recovery plan и пройдите контрольный список перед открытием.
Зафиксируйте root cause и внедрите изменения процесса (патчи, права, мониторинг).
Заключение
Инцидент с взломом сайта — это стресс, но грамотный incident response превращает хаос в управляемую процедуру. Самое важное: изоляция, сохранение артефактов, осмысленный log review, обязательный rotate secrets и восстановление по понятному recovery plan. Тогда вы не просто «поднимете сайт», а реально снизите риск повторного компромета.


