☰
WORDPRESS / PRACTICE

Как запретить выполнение PHP в каталоге uploads WordPress через Nginx

Как запретить выполнение PHP в каталоге uploads WordPress через Nginx

Каталог <code>wp-content/uploads</code> в WordPress предназначен для изображений, документов, видео и других загруженных медиафайлов. Исполняемого PHP-кода там быть не должно.

Если злоумышленник воспользуется уязвимостью плагина, темы или формы загрузки и сохранит в uploads файл вроде <code>shell.php</code>, стандартное правило Nginx для обработки PHP может передать его PHP-FPM. В результате файл запустится на сервере. Надёжная базовая мера защиты — отдельно запретить выполнение PHP и родственных форматов в каталоге загрузок.

Почему в uploads не должен выполняться PHP

WordPress хранит загруженные медиафайлы преимущественно в <code>wp-content/uploads</code>, часто распределяя их по годам и месяцам. Обычный пользователь или редактор должен загружать туда контент, а не серверные скрипты.

Само наличие PHP-файла в uploads ещё не означает, что он будет выполнен. Риск возникает, когда веб-сервер позволяет обратиться к нему через URL и передаёт запрос PHP-FPM. Веб-шелл в таком каталоге может использоваться для выполнения команд, кражи данных или дальнейшего заражения сайта.

Запрет на уровне Nginx создаёт дополнительный защитный барьер, даже если другая ошибка позволила загрузить файл с опасным расширением.

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

Правило Nginx для блокировки PHP-файлов

Откройте конфигурацию нужного виртуального хоста Nginx. Обычно это файл в конфигурации sites-available или другое определение <code>server</code>, обслуживающее домен. Правило нужно добавить внутри блока <code>server</code>, рядом с другими блоками <code>location</code>.

Используйте регулярное выражение, которое охватывает PHP, PHTML и PHAR независимо от регистра букв:

location ~* ^/wp-content/uploads/.*\.(php|phtml|phar)$ {
    deny all;
}

Почему правило должно находиться перед общим PHP location

В типичной конфигурации есть общий обработчик вроде <code>location ~ \.php$</code>, который передаёт PHP-запросы в PHP-FPM. Если оба блока являются регулярными location, специализированное правило для uploads нужно разместить перед ним.

Nginx проверяет регулярные location в порядке их появления и использует первый подходящий вариант. Если общий PHP-обработчик сработает раньше, запрос к файлу в uploads может быть передан интерпретатору.

  • Добавляйте правило в контексте <code>server</code>, а не внутри другого блока <code>location</code>.
  • Не заменяйте этим правилом общий PHP-обработчик: они выполняют разные задачи.
  • Если в конфигурации есть несколько блоков <code>server</code>, изменяйте тот, который действительно обслуживает домен.

Как безопасно применить изменения

После редактирования не перезагружайте Nginx сразу. Сначала проверьте синтаксис конфигурации. Приведённая ниже команда не применит ошибочные изменения, если проверка завершится неудачно:

nginx -t && systemctl reload nginx

Если проверка завершилась ошибкой

Изучите сообщение Nginx: обычно оно содержит путь к файлу и номер строки. Наиболее распространённые причины — пропущенная точка с запятой, неправильный контекст <code>location</code> или редактирование не того конфигурационного файла.

Если в вашей системе нет доступа к <code>systemctl</code>, перезагрузка может выполняться другим способом, например через init-скрипт или панель управления сервером. Важно сохранить принцип: сначала проверка, затем graceful reload.

Как проверить, что выполнение действительно заблокировано

Для практической проверки создайте в тестовой среде или временно на сайте файл с расширением <code>.php</code> в каталоге uploads. Не помещайте в него опасный код — достаточно простого текста или другого безопасного тестового содержимого. Затем обратитесь к URL этого файла.

Ожидаемый результат — ответ HTTP 403 Forbidden или другой ответ, подтверждающий отказ в доступе. Важно проверить именно URL с каталогом uploads, а не только наличие файла на диске.

  • Проверьте расширения в нижнем и верхнем регистре, например .php и .PHP.
  • Убедитесь, что запрос попадает именно в нужный блок <code>server</code>.
  • После проверки удалите тестовый файл.
  • При необходимости просмотрите access log и error log Nginx, чтобы увидеть, как обрабатывается запрос.
curl -I https://example.com/wp-content/uploads/2025/01/test.php

Поиск уже существующих опасных файлов

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

Проверьте каталог на наличие файлов с расширениями, которые не должны там появляться:

find /path/to/wordpress/wp-content/uploads -type f \( -iname "*.php" -o -iname "*.phtml" -o -iname "*.phar" \) -print

Что делать с найденными файлами

Не удаляйте все найденные файлы без проверки: иногда администратор намеренно хранит там служебные или тестовые файлы. В то же время PHP-файл в стандартном uploads выглядит подозрительно и требует объяснения.

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

  • Не открывайте подозрительный файл в браузере.
  • Не запускайте его через PHP CLI во время проверки.
  • Сравнивайте код с чистой копией WordPress или соответствующего плагина, полученной только из надёжного источника.

Нестандартные каталоги загрузок и типичные ошибки

Не каждый сайт использует стандартный URL <code>/wp-content/uploads/</code>. Каталог может быть изменён настройками WordPress, плагином оптимизации, CDN или собственной структурой проекта. В таком случае замените путь в регулярном выражении на фактический URL-префикс.

Учтите, что путь в правиле Nginx — это URL, а не локальный путь файловой системы. Например, <code>/var/www/site/media</code> не следует напрямую подставлять вместо <code>/wp-content/uploads/</code>, если через браузер каталог доступен как <code>/media/</code>.

  • Не добавляйте правило только в конфигурацию Apache, если запросы обрабатывает Nginx.
  • Не используйте блокировку только для файлов с точным расширением в нижнем регистре.
  • Не полагайтесь только на запрет PHP в корневом файле .htaccess, если перед сайтом работает Nginx.
  • Убедитесь, что правило не блокирует нужные статические файлы из-за слишком широкого регулярного выражения.

Дополнительные меры защиты WordPress

Блокировка выполнения PHP в uploads — важная, но не единственная мера. Она не устраняет уязвимость, благодаря которой файл был загружен, и не защищает от вредоносного JavaScript, подменённых изображений или заражённых файлов других типов.

Поддерживайте WordPress, тему и плагины в актуальном состоянии, удаляйте неиспользуемые компоненты, ограничивайте права на запись и используйте резервные копии. Для форм загрузки применяйте проверку типа и размера файла, но помните: MIME-тип и расширение можно подделать, поэтому последний барьер должен оставаться на уровне веб-сервера.

Если сайт обслуживается через CDN, WAF или панель управления хостингом, проверьте, не перезаписывает ли их конфигурация ваши правила Nginx.

Частые вопросы

Достаточно ли запретить только файлы .php?

Для базовой защиты этого недостаточно. Следует также блокировать .phtml и .phar, поскольку конфигурация сервера или дополнительные обработчики могут рассматривать их как исполняемые форматы.

Удалит ли правило уже загруженный веб-шелл?

Нет. Правило только запрещает HTTP-доступ к соответствующим файлам. Уже существующие файлы нужно отдельно найти, изолировать, проверить и удалить либо восстановить сайт из чистой резервной копии.

Почему после добавления правила файл всё ещё открывается?

Проверьте, внесены ли изменения в активный блок server, выполнены ли <code>nginx -t</code> и reload, а также не перехватывает ли запрос другой прокси или CDN. Просмотрите конфигурацию командой <code>nginx -T</code> и журналы Nginx.

Нужно ли блокировать выполнение PHP в других каталогах?

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

Вывод

Запрет выполнения PHP, PHTML и PHAR в <code>wp-content/uploads</code> — простая настраиваемая мера, которая снижает последствия опасной загрузки файлов в WordPress. Добавьте специальный location перед общим PHP-обработчиком, проверьте конфигурацию через <code>nginx -t</code> и выполните безопасную перезагрузку Nginx.

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

← Все материалы WordPress