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

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


Одна из самых больших ошибок, которую разработчики совершают после взлома, — пытаются исправить только видимые повреждения. Они удаляют спам-страницы, меняют пароль администратора, обновляют несколько плагинов и предполагают, что проблема решена. Это может устранить симптом, но не обязательно устранит уязвимость, которая изначально позволила злоумышленнику проникнуть внутрь. Если исходная точка входа всё ещё существует, злоумышленник может просто вернуться.

Я придерживаюсь другого подхода. После компрометации сайта я предполагаю, что необходимо проверить всё, связанное с этим приложением. Сюда входят общедоступные файлы, база данных, конфигурация сервера, запланированные задания, учётные записи администраторов, права доступа к файлам, ключи API, каталоги загрузки и система аутентификации. Цель состоит не просто в очистке сайта. Цель — восстановить доверие к среде.

В этой статье объясняется модель безопасности, которую я использую при усилении защиты пользовательского PHP- и MySQL-сайта. Некоторые из этих методов также применимы к WordPress, Laravel, Symfony и другим платформам, но приведённые здесь примеры в основном посвящены традиционным PHP-приложениям, работающим на Apache.

Начните с правильного предположения

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

Например, злоумышленник может загрузить веб-шелл в каталог изображений, внедрить PHP в легитимный файл приложения, создать скрытую учётную запись администратора, изменить запланированную задачу или вставить вредоносный JavaScript в базу данных. Он также может создавать файлы с безобидно выглядящими именами, такими как cache.php, class.api.php или system-helper.php, чтобы вредоносное ПО не выделялось среди легитимного кода приложения.

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

Полезная команда Linux:

find /var/www/html -type f -mtime -14 -print

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

Также можно выполнить поиск PHP-файлов внутри каталогов, в которых обычно должно содержаться только статическое содержимое:

find /var/www/html/uploads -type f \( -name "*.php" -o -name "*.phtml" -o -name "*.phar" \)

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

Смените все учётные данные, которые могли быть раскрыты

Изменить пароль администратора веб-сайта недостаточно. Если злоумышленник получил доступ к серверу или файлам приложения, он мог прочитать пароли базы данных, учётные данные API, пароли SMTP, секретные ключи Stripe, ключи сессий и другие средства аутентификации.

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

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

DB_HOST=localhost
DB_DATABASE=production
DB_USERNAME=website_user
DB_PASSWORD=replace_this_password

STRIPE_SECRET_KEY=replace_this_key
OPENAI_API_KEY=replace_this_key

Эти файлы ни в коем случае не должны быть доступны через публичный веб-сервер. Если кто-то может перейти по адресу https://example.com/.env и скачать этот файл, значит, в конфигурации приложения есть серьезная проблема.

В Apache я явно блокирую доступ к конфиденциальным файлам.

<FilesMatch "^(\.env|\.git|composer\.(json|lock)|package(-lock)?\.json)$">
    Require all denied
</FilesMatch>

Это не заменяет правильную структуру каталогов, но дает еще один уровень защиты.

Храните конфиденциальную конфигурацию за пределами общедоступного корня веб-сайта

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

Вместо хранения учетных данных базы данных в файле вроде:

/public_html/config.php

я предпочитаю использовать что-то ближе к следующему:

/home/account/private/config.php
/home/account/public_html/index.php

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

Это важно, поскольку неправильная настройка сервера действительно случается. Обработчик PHP может дать сбой. Конфигурация Apache может измениться. Резервная копия файла может случайно стать доступной для скачивания. Хранение секретов за пределами доступного из веба каталога уменьшает количество способов их утечки.

Отключение отображения содержимого каталогов

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

Я глобально отключаю индексацию каталогов для приложения.

Options -Indexes

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