Segurança do GLPI: Hardening e Boas Práticas

Checklist prático de hardening de GLPI em produção: webroot em public/, virtual host Nginx, headers de segurança, cookie de sessão Secure atrás de proxy, permissões, contas e diagnóstico SQL - direto da sustentação de ambientes NexTool.

Hardening de GLPI raramente cai por um zero-day. Cai pelo instalador esquecido, pelo webroot na raiz errada e pelo cookie de sessão sem a flag Secure atrás do proxy. Este guia é o checklist que aplicamos na sustentação de ambientes de clientes: os comandos, o virtual host e as consultas de diagnóstico que usamos para fechar a superfície de ataque de um GLPI em produção.

Por onde um GLPI é comprometido de verdade

Na sustentação de dezenas de ambientes, o padrão se repete: o comprometimento quase nunca vem de uma falha exótica do core. Vem de configuração. Os quatro vetores que mais encontramos, em ordem, são: (1) install/install.php nunca removido depois do deploy; (2) DocumentRoot apontando para a raiz da instalação em vez de public/, o que deixa files/_log/ e backups de config servíveis como texto; (3) credenciais padrão (glpi/glpi) ainda ativas; e (4) TLS terminando no proxy reverso com o backend em HTTP puro e o cookie de sessão sem Secure. Nenhum desses precisa de exploit, só de um curl. Comece a auditoria testando exatamente isso:

# 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

Se qualquer um desses devolver conteúdo, pare tudo: o ambiente está exposto agora, e a correção é prioridade zero.

1. Feche a superfície: webroot em public/ e sem sobras de instalação

  1. Aponte o DocumentRoot (ou root no Nginx) para /var/www/glpi/public, nunca para /var/www/glpi. Desde o GLPI 10 apenas a pasta public/ deve ser o webroot.
  2. Remova install/install.php após concluir a instalação ou o upgrade. O upgrade recria esse arquivo: o erro comum é atualizar o GLPI e esquecer de removê-lo de novo.
  3. Garanta que config/, files/ e qualquer .bak ou .git fiquem fora do alcance do servidor web.

2. Virtual host: raiz correta, headers e só o index.php executando PHP

O padrão do GLPI 10 é rotear tudo por public/index.php e não deixar nenhum outro .php ser executado diretamente. Este é o server block que usamos como base no 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;
    }
}

No Apache, o equivalente é DocumentRoot /var/www/glpi/public com o bloco <Directory> restrito e os mesmos cabeçalhos via Header set. Um cuidado de campo: só habilite Strict-Transport-Security (HSTS) depois que o certificado estiver 100%. Com HSTS ativo e um TLS quebrado você bloqueia o domínio inteiro no navegador dos usuários pelo tempo do max-age.

3. Sessão e cookies: o vazamento silencioso atrás do proxy

Este é o achado que mais passa despercebido. Quando o TLS termina no proxy (Nginx/HAProxy) e o GLPI roda em HTTP no backend, o cookie de sessão precisa continuar marcado como Secure e HttpOnly. Em Configuração > Geral, na aba de segurança, force cookies seguros e uma política de senha (tamanho mínimo, complexidade, expiração). Sem isso, o cookie de sessão trafega no salto interno HTTP sem Secure e basta capturar o tráfego nesse segmento para sequestrar a sessão de um técnico logado. Ajuste também o tempo de vida da sessão para algo compatível com o risco do ambiente, em vez do padrão longo.

4. Contas e autenticação

Troque imediatamente as senhas de glpi, tech, normal e post-only, ou desative as que não usa. Rode este diagnóstico direto no banco para mapear o que ainda depende de senha local (authtype = 1) e é candidato a MFA/SSO ou desativação:

-- Contas padrão do GLPI ainda ativas
SELECT name, is_active, last_login
FROM   glpi_users
WHERE  name IN ('glpi','tech','normal','post-only');

-- Todas as contas com senha LOCAL ativa (authtype = 1)
-- authtype: 1=local  2=mail  3=LDAP  4=externa  5=CAS
SELECT id, name, is_active, last_login
FROM   glpi_users
WHERE  authtype = 1 AND is_active = 1
ORDER  BY last_login;

A recomendação para produção: SSO (Azure AD/Entra ID ou outro provedor) com MFA, e login local restrito a uma única conta de emergência (break-glass) com senha forte guardada em cofre. O core do GLPI não tem MFA nativo nem bloqueio por tentativas: para MFA use um plugin apropriado ou o próprio SSO; para brute force, coloque o GLPI atrás de fail2ban lendo o log de acesso do proxy. Veja também nosso guia de SSO com Azure AD/Entra ID.

5. Permissões: código só-leitura, escrita só no que precisa

O princípio é simples: o usuário do PHP-FPM (www-data) deve ler o código, mas nunca escrevê-lo. A única árvore com escrita é o GLPI_VAR_DIR. Assim, mesmo uma falha na aplicação não consegue persistir código malicioso no diretório servido.

DiretórioPapelDono:grupoEscrita www-data
/var/www/glpiCódigo + webroot public/root:www-dataNão (750 / 640)
/etc/glpiConfig (config_db.php)root:www-dataNão (750 / 640)
/var/lib/glpiGLPI_VAR_DIR (files, cache, sessões)www-data:www-dataSim (750)
/var/log/glpiLogs da aplicaçãowww-data:www-dataSim (750)

Separar config/ e files/ para fora do webroot (via GLPI_CONFIG_DIR e GLPI_VAR_DIR) é o layout que adotamos por padrão: se um dia o webroot for exposto por engano, config e dados não vão junto.

6. Atualizações e monitoramento contínuo

Mantenha a versão em dia. A maioria dos CVEs do GLPI já tem patch quando vira notícia; o risco real é o ambiente parado três versões atrás. Monitore tentativas de autenticação (picos de falha de login sugerem brute force) no Zabbix/Grafana e acompanhe as CVEs da versão instalada. Para isso usamos o módulo CVE Scan, que cruza a versão do GLPI com as CVEs conhecidas e audita pontos do ambiente. E não trate hardening sem plano de recuperação: veja o guia de backup e disaster recovery.

Erros comuns que vemos na sustentação

  • Backup de config no webroot: alguém salva config_db.php.bak antes de editar; como .bak não é executado pelo PHP, o servidor entrega a credencial do banco em texto puro.
  • Alias legado sobrevivendo: o vhost novo aponta para public/, mas um Alias /glpi antigo continua expondo a raiz.
  • HSTS antes do certificado: ativar HSTS com TLS incompleto tranca o domínio no navegador dos usuários.
  • Login local desativado sem break-glass: cortam o login local confiando 100% no SSO e, quando o SSO cai, ninguém entra como admin.

Fazer isso uma vez é fácil; manter em dezenas de ambientes de clientes, com upgrades recorrentes recriando o install/, é trabalho de sustentação. É exatamente o que a NexTool faz: a sustentação de GLPI da NexTool valida o webroot, endurece o virtual host, revisa permissões e roda essa bateria de verificação como parte do ciclo de manutenção.


Este conteúdo foi produzido com auxílio de inteligência artificial e revisado pela equipe Nextool Solutions.

Perguntas Frequentes

Faça um curl para /install/install.php, /files/_log/php-errors.log e /config/config_db.php.bak. O esperado é 403 ou 404; qualquer resposta 200 com conteúdo significa exposição. A causa quase sempre é o DocumentRoot apontando para a raiz da instalação em vez de public/.

Funciona, mas é inseguro. Com a raiz errada, arquivos como files/_log/ e backups de config viram texto servível pelo servidor web. Desde o GLPI 10, public/ é o único webroot correto porque isola o index.php do resto da instalação.

Não no core. Coloque o GLPI atrás de fail2ban lendo o log de acesso do proxy reverso, ou use SSO/MFA para reduzir a superfície. Em paralelo, monitore picos de falha de login no Zabbix ou Grafana, que são o sinal típico de ataque por força bruta.

Em Configuração > Geral, aba de segurança, habilite cookies seguros; garanta que o proxy encaminhe X-Forwarded-Proto e que o GLPI reconheça que está sob HTTPS. Sem a flag Secure, o cookie de sessão trafega no salto HTTP interno e pode ser capturado nesse segmento.

Não nativamente no core. Use um plugin de MFA (TOTP) ou SSO com Azure AD/Entra ID ou Okta, que já trazem MFA. Mantenha sempre uma conta local de emergência (break-glass) com senha forte, para não perder o acesso administrativo se o SSO cair.

Precisa de ajuda?