Аудит безпеки сайту на Drupal
Drupal історично має хорошу репутацію в безпеці — виділена Security Team, система Security Advisory (SA), регулярні патчі. Тим не менше застарілі модулі, неправильна конфігурація та кастомний код створюють вразливості.
Інструменти аудиту
# Перевірка оновлень безпеки
drush pm:security
# Детальний список вразливих пакетів
composer audit
# Drupal Security Scanner (зовнішній)
# https://www.drupal.org/security/advisories
Контрольний список
Ядро та модулі:
# Чи всі оновлення безпеки застосовані?
drush pm:security --format=table
# Версія PHP
php -v # мінімум 8.1, рекомендується 8.3
Права доступу до файлів:
# settings.php повинен бути тільки для читання
stat web/sites/default/settings.php
# 444 або 400 — правильно
# 644 або 755 — занадто відкрито
# Директорія files
find web/sites/default/files -name "*.php" -type f
# PHP-файли в /files — ознака компрометації
# Директорії з правильними правами
find web -type d -perm /o+w -not -path "*/\.*"
Аудит settings.php:
// Має бути:
$settings['hash_salt'] = 'довга-випадкова-строка'; // унікальна для кожного сайту
$config['system.logging']['error_level'] = 'hide'; // не показувати помилки
$settings['trusted_host_patterns'] = [ // список дозволених хостів
'^yourdomain\.com$',
'^www\.yourdomain\.com$',
];
// Не повинно бути:
// $settings['rebuild_access'] = TRUE; // тільки для розробки
// $config['system.performance']['cache']['page']['max_age'] = 0; // не в production
Trusted Host Patterns — критично. Без цієї настройки сайт уразливий до Host header injection атак.
Користувачі та ролі:
# Список адміністраторів
drush sql:query "SELECT name, mail FROM users u JOIN user__roles ur ON u.uid = ur.entity_id WHERE ur.roles_target_id = 'administrator'"
# Перевірити дозволи анонімних користувачів
drush role:list --filter=anonymous
Конфігурація безпеки:
# Чи включена Security Review?
composer require drupal/security_review
drush en security_review -y
drush secrev --store # запустити перевірку
Security Review перевіряє: права файлів, дозволи ролей, критичні настройки PHP, input filters, приватні файли.
Аналіз кастомного коду
Вразливості XSS:
# Пошук небезпечного виводу в Twig
grep -r "raw" web/themes/custom/ web/modules/custom/
# {{ var | raw }} без попередньої санітизації — вразливо
# В PHP
grep -r "print_r\(\$_\|echo \$_\|print \$_" web/modules/custom/
SQL Injection:
// Небезпечно (не робити):
$result = \Drupal::database()->query("SELECT * FROM node WHERE title = '" . $input . "'");
// Правильно:
$result = \Drupal::database()->query(
"SELECT * FROM node WHERE title = :title",
[':title' => $input]
);
Захист CSRF:
// Всі форми повинні використовувати FormAPI або явну перевірку токена
$form['#token'] = 'my_operation';
// Або в кастомному контролері
$this->csrfToken->validate($token, 'my-route');
Завантаження файлів:
# Дозволені розширення файлів у полях
drush config:get field.field.node.article.field_attachment | grep "file_extensions"
# Ніколи не дозволяти: php, phtml, phar, js, html
Заголовки безпеки
// services.yml або кастомний EventSubscriber
class SecurityHeadersSubscriber implements EventSubscriberInterface {
public function onResponse(ResponseEvent $event): void {
$response = $event->getResponse();
$response->headers->set('X-Content-Type-Options', 'nosniff');
$response->headers->set('X-Frame-Options', 'SAMEORIGIN');
$response->headers->set('Referrer-Policy', 'strict-origin-when-cross-origin');
$response->headers->set('Permissions-Policy', 'camera=(), microphone=(), geolocation=()');
}
}
Приватні файли
// settings.php: зберігати приватні файли поза web root
$settings['file_private_path'] = '/var/private/drupal-files';
Документи доступні тільки для авторизованих користувачів — ніколи в sites/default/files (публічній директорії).
Терміни
Аудит безпеки Drupal зі звітом — 1–2 дні. Усунення критичних вразливостей — додатково 1–3 дні.







