Безопасность GLPI: харденинг и лучшие практики

Практический чек-лист харденинга GLPI в продакшене: webroot в public/, virtual host Nginx, заголовки безопасности, cookie сессии с флагом Secure за прокси, права доступа к файлам, учётные записи и SQL-диагностика — напрямую из опыта сопровождения сред NexTool.

В этой статьеРазделов: 8

GLPI редко взламывают через zero-day. Его взламывают через забытый установщик, webroot в неправильном корне и cookie сессии без флага Secure за прокси. Это руководство — чек-лист, который мы применяем при сопровождении клиентских сред: команды, virtual host и диагностические запросы, которые мы используем, чтобы закрыть поверхность атаки GLPI в продакшене.

Как GLPI компрометируют на самом деле

При сопровождении десятков сред картина повторяется: компрометация почти никогда не происходит из-за экзотической уязвимости ядра. Её причина — конфигурация. Четыре вектора, которые мы встречаем чаще всего, по порядку: (1) install/install.php, так и не удалённый после развёртывания; (2) DocumentRoot, указывающий на корень установки вместо public/, из-за чего files/_log/ и резервные копии конфигурации отдаются как текст; (3) всё ещё активные учётные данные по умолчанию (glpi/glpi); и (4) TLS, завершающийся на обратном прокси, при бэкенде на чистом HTTP и cookie сессии без Secure. Ни для одного из них не нужен эксплойт — достаточно curl. Начните аудит с проверки именно этого:

# Instalador ainda no ar? (esperado: 404)
curl -s -o /dev/null -w "%{http_code}\n" https://glpi.cliente.com.br/install/install.php

# Log de erros exposto? (esperado: 403/404, NUNCA 200 com conteúdo)
curl -s https://glpi.cliente.com.br/files/_log/php-errors.log | head

# Backup de config vazando credencial do banco? (esperado: nada)
curl -s https://glpi.cliente.com.br/config/config_db.php.bak | head

Если любой из этих запросов вернёт содержимое, остановите всё: среда открыта прямо сейчас, и исправление — наивысший приоритет.

1. Закройте поверхность: webroot в public/ и никаких остатков установки

  1. Направьте DocumentRoot (или root в Nginx) на /var/www/glpi/public, а не на /var/www/glpi. Начиная с GLPI 10 webroot должна быть только папка public/.
  2. Удалите install/install.php после завершения установки или обновления. Обновление заново создаёт этот файл: типичная ошибка — обновить GLPI и забыть удалить его снова.
  3. Убедитесь, что config/, files/ и любые .bak или .git находятся вне досягаемости веб-сервера.

2. Virtual host: правильный корень, заголовки и PHP только через index.php

Стандарт GLPI 10 — маршрутизировать всё через public/index.php и не позволять напрямую исполнять никакой другой .php. Вот server block, который мы используем как основу в Nginx:

# /etc/nginx/sites-available/glpi.conf
server {
    listen 443 ssl;
    http2 on;
    server_name glpi.cliente.com.br;

    root /var/www/glpi/public;   # nunca /var/www/glpi
    index index.php;

    ssl_certificate     /etc/letsencrypt/live/glpi.cliente.com.br/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/glpi.cliente.com.br/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;

    # Cabeçalhos de segurança
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

    location / {
        try_files $uri /index.php$is_args$args;
    }

    # Somente o index.php roteia PHP
    location ~ ^/index\.php$ {
        include fastcgi_params;
        fastcgi_pass unix:/run/php/php8.2-fpm.sock;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }

    # Qualquer outro .php: negar
    location ~ \.php$ {
        return 404;
    }
}

В Apache эквивалент — DocumentRoot /var/www/glpi/public с ограниченным блоком <Directory> и теми же заголовками через Header set. Совет из практики: включайте Strict-Transport-Security (HSTS) только после того, как сертификат полностью в порядке. С активным HSTS и сломанным TLS вы блокируете весь домен в браузерах пользователей на срок max-age.

Это находка, которую чаще всего упускают. Когда TLS завершается на прокси (Nginx/HAProxy), а GLPI работает по HTTP на бэкенде, cookie сессии по-прежнему должен быть помечен как Secure и HttpOnly. В Настройки > Общие, на вкладке безопасности, принудительно включите защищённые cookie и политику паролей (минимальная длина, сложность, срок действия). Без этого cookie сессии передаётся на внутреннем HTTP-участке без Secure, и достаточно перехватить трафик в этом сегменте, чтобы захватить сессию вошедшего специалиста. Также настройте время жизни сессии в соответствии с уровнем риска среды вместо длинного значения по умолчанию.

4. Учётные записи и аутентификация

Немедленно смените пароли glpi, tech, normal и post-only или отключите те, которые не используете. Выполните эту диагностику прямо в базе данных, чтобы выявить, что всё ещё зависит от локального пароля (authtype = 1) и является кандидатом на MFA/SSO или отключение:

-- Default GLPI accounts still active
SELECT name, is_active, last_login
FROM   glpi_users
WHERE  name IN ('glpi','tech','normal','post-only');

-- All accounts with an active LOCAL password (authtype = 1)
-- authtype: 1=local  2=mail  3=LDAP  4=external  5=CAS
SELECT id, name, is_active, last_login
FROM   glpi_users
WHERE  authtype = 1 AND is_active = 1
ORDER  BY last_login;

Рекомендация для продакшена: SSO (Azure AD/Entra ID или другой провайдер) с MFA, а локальный вход ограничен одной аварийной учётной записью (break-glass) с надёжным паролем, хранящимся в хранилище секретов. В ядре GLPI нет встроенной MFA и блокировки по числу попыток: для MFA используйте подходящий плагин или сам SSO; против перебора паролей поставьте GLPI за fail2ban, читающий журнал доступа прокси. См. также наше руководство по SSO с Azure AD/Entra ID.

5. Права доступа: код только для чтения, запись только там, где нужно

Принцип прост: пользователь PHP-FPM (www-data) должен читать код, но никогда не записывать его. Единственное дерево с правом записи — GLPI_VAR_DIR. Так даже уязвимость в приложении не сможет закрепить вредоносный код в обслуживаемом каталоге.

КаталогНазначениеВладелец:группаЗапись для www-data
/var/www/glpiКод + webroot public/root:www-dataНет (750 / 640)
/etc/glpiКонфигурация (config_db.php)root:www-dataНет (750 / 640)
/var/lib/glpiGLPI_VAR_DIR (files, кэш, сессии)www-data:www-dataДа (750)
/var/log/glpiЖурналы приложенияwww-data:www-dataДа (750)

Вынос config/ и files/ за пределы webroot (через GLPI_CONFIG_DIR и GLPI_VAR_DIR) — схема, которую мы применяем по умолчанию: если однажды webroot по ошибке окажется открыт, конфигурация и данные не утекут вместе с ним.

6. Обновления и непрерывный мониторинг

Поддерживайте версию в актуальном состоянии. Для большинства CVE GLPI патч уже существует к моменту, когда о них пишут в новостях; реальный риск — среда, застрявшая на три версии позади. Отслеживайте попытки аутентификации (всплески неудачных входов указывают на перебор паролей) в Zabbix/Grafana и следите за CVE установленной версии. Для этого мы используем модуль CVE Scan, который сопоставляет версию GLPI с известными CVE и проверяет ключевые точки среды. И не занимайтесь харденингом без плана восстановления: см. руководство по резервному копированию и аварийному восстановлению.

Типичные ошибки, которые мы видим при сопровождении

  • Резервная копия конфигурации в webroot: кто-то сохраняет config_db.php.bak перед редактированием; поскольку .bak не исполняется PHP, сервер отдаёт учётные данные базы данных открытым текстом.
  • Уцелевший устаревший alias: новый vhost указывает на public/, но старый Alias /glpi продолжает открывать корень.
  • HSTS до сертификата: включение HSTS при незавершённой настройке TLS блокирует домен в браузерах пользователей.
  • Локальный вход отключён без break-glass: локальный вход отключают, полностью полагаясь на SSO, а когда SSO падает, никто не может войти как администратор.

Сделать это один раз несложно; поддерживать это в десятках клиентских сред, где регулярные обновления заново создают install/, — это работа сопровождения. Именно этим и занимается NexTool: сопровождение GLPI от NexTool проверяет webroot, усиливает virtual host, пересматривает права доступа и запускает эту серию проверок в рамках цикла обслуживания.


Проверено командой NexTool Solutions.

Часто задаваемые вопросы

Выполните curl к /install/install.php, /files/_log/php-errors.log и /config/config_db.php.bak. Ожидаемый ответ — 403 или 404; любой ответ 200 с содержимым означает утечку. Причина почти всегда в том, что DocumentRoot указывает на корень установки вместо public/.

Работает, но небезопасно. При неправильном корне такие файлы, как files/_log/ и резервные копии конфигурации, становятся текстом, который отдаёт веб-сервер. Начиная с GLPI 10 public/ — единственный правильный webroot, потому что он изолирует index.php от остальной установки.

В ядре — нет. Поставьте GLPI за fail2ban, читающий журнал доступа обратного прокси, или используйте SSO/MFA, чтобы сократить поверхность атаки. Параллельно отслеживайте всплески неудачных входов в Zabbix или Grafana — это типичный признак атаки перебором.

В «Настройки > Общие», на вкладке безопасности, включите защищённые cookie; убедитесь, что прокси передаёт X-Forwarded-Proto и что GLPI распознаёт, что работает под HTTPS. Без флага Secure cookie сессии передаётся на внутреннем HTTP-участке и может быть перехвачен в этом сегменте.

Не встроенно в ядре. Используйте плагин MFA (TOTP) или SSO с Azure AD/Entra ID или Okta, где MFA уже есть. Всегда сохраняйте аварийную локальную учётную запись (break-glass) с надёжным паролем, чтобы не потерять административный доступ, если SSO упадёт.

Нужна помощь?