Каталог <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. Webshell у такому каталозі може використовуватися для виконання команд, крадіжки даних або подальшого зараження сайту.
Заборона на рівні Nginx створює додатковий захисний бар’єр навіть у випадку, якщо інша помилка дозволила завантажити файл із небезпечним розширенням.
- У uploads мають зберігатися медіафайли, а не скрипти.
- Перевірка розширення під час завантаження не замінює правила вебсервера.
- Заборона виконання не видаляє файли, які вже потрапили на сервер.
Правило Nginx для блокування PHP-файлів
Відкрийте конфігурацію потрібного віртуального хоста Nginx — зазвичай це файл у конфігурації sites-available або інше server-визначення, яке обслуговує домен. Правило потрібно додати всередині блоку <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. Спеціалізоване правило для uploads має бути розташоване перед ним, якщо обидва блоки є регулярними location.
Nginx перевіряє регулярні location у порядку їх появи та використовує перший відповідний варіант. Якщо загальний PHP-обробник спрацює раніше, запит до файлу в uploads може бути переданий інтерпретатору.
- Додавайте правило в контексті server, а не всередині іншого location.
- Не замінюйте загальний PHP-обробник цим правилом: вони виконують різні завдання.
- Якщо у конфігурації є кілька server-блоків, змінюйте той, який реально обслуговує домен.
Як застосувати зміни без ризику для сайту
Після редагування не перезавантажуйте 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.
- Переконайтеся, що запит потрапляє саме в потрібний server-блок.
- Після перевірки видаліть тестовий файл.
- За потреби перегляньте access log та error log Nginx, щоб побачити, як обробляється запит.
curl -I https://example.com/wp-content/uploads/2025/01/test.php
Пошук уже наявних небезпечних файлів
Правило Nginx блокує доступ до файлів через вебсервер, але не сканує і не видаляє їх. Якщо сайт уже був скомпрометований, у uploads можуть залишатися webshell або інший шкідливий код.
Перевірте каталог на наявність файлів із розширеннями, які не повинні там з’являтися:
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, оскільки серверна конфігурація або додаткові обробники можуть ставитися до них як до виконуваних форматів.
Чи видалить правило вже завантажений webshell?
Ні. Правило лише забороняє HTTP-доступ до відповідних файлів. Наявні файли потрібно окремо знайти, ізолювати, перевірити та видалити або відновити сайт із чистої резервної копії.
Чому після додавання правила файл усе ще відкривається?
Перевірте, чи зміни внесені в активний server-блок, чи було виконано nginx -t і reload, а також чи не перехоплює запит інший проксі або CDN. Перегляньте конфігурацію командою nginx -T та журнали Nginx.
Чи потрібно блокувати виконання PHP в інших каталогах?
Так, якщо там зберігаються завантаження або файли, які не повинні виконуватися. Шлях і правила залежать від структури конкретного сайту, тому їх потрібно перевіряти окремо, не копіюючи конфігурацію без аналізу.
Висновок
Заборона виконання PHP, PHTML і PHAR у <code>wp-content/uploads</code> — проста налаштовувана міра, яка зменшує наслідки небезпечного завантаження файлів у WordPress. Додайте спеціальний location перед загальним PHP-обробником, перевірте конфігурацію через <code>nginx -t</code> і виконайте безпечне перезавантаження Nginx.
Після цього обов’язково проскануйте uploads на вже наявні підозрілі файли. Захист буде повнішим, якщо поєднати правило вебсервера з оновленнями, обмеженими правами доступу, резервними копіями та перевіркою журналів.