Cerebro Studio · Backlog · Changelog
RioNoTeatro • /www/wwwroot/rionoteatro.com.br/docs/BACKLOG.md
Abrir Studio Projeto externo em modo read-only; encaminhamento permitido, escrita bloqueada.

Backlog Unificado

Projeto: RioNoTeatro. Fonte principal: /www/wwwroot/rionoteatro.com.br/docs/BACKLOG.md.

Modo read-only: ações de escrita ficam disponíveis apenas para o Cérebro.

Sem itens pendentes em /www/wwwroot/rionoteatro.com.br/docs/BACKLOG.md.

Especificações Disponíveis (fora da fila pendente)

Detalhe do BK Selecionado

/www/wwwroot/rionoteatro.com.br/docs/backlog/BK-341-auditoria-seguranca-pagamentos-mp.md • 2026-07-25T17:37:01.923Z

BK-341 - Auditoria de segurança focada em pagamentos (Mercado Pago) - Julho/2026

Contexto

Auditoria pedida pelo dono do site em 24/07/2026, com foco nos dois sites da VPS que processam pagamento ao público: rionoteatro.com.br (Mercado Pago) e seuimovel.rio.br (PagSeguro, não Mercado Pago — corrigir premissa original).

Já existia uma auditoria anterior em BK-272 (docs/backlog/BK-272-auditoria-seguranca-geral.md, abril/2026) que recomendava um bloqueio de .bak/.bkp no Nginx. Confirmado nesta auditoria que essa recomendação nunca foi aplicada no vhost real (/www/server/panel/vhost/nginx/rionoteatro.com.br.conf continuava com a regex antiga na data desta auditoria), e mesmo a regex proposta em BK-272 não cobriria o padrão real de nomes de backup usado no projeto (ver item 1).

Todos os achados abaixo foram confirmados ao vivo (download real via HTTPS ou leitura direta do código/config), não são teóricos.

Status geral

  • [x] Item 1 (CRÍTICO — exposição de backups) — corrigido e validado em 24/07/2026
  • [x] Item 2 (ALTO — rate limit /admin/) — corrigido e validado em 25/07/2026
  • [x] Item 3 (ALTO — cookie de sessão sem flags) — corrigido e validado em 25/07/2026
  • [x] Item 4 (ALTO — headers de segurança ausentes) — corrigido e validado em 25/07/2026
  • [x] Item 5 (ALTO — TLS 1.1 habilitado) — corrigido e validado em 25/07/2026
  • [~] Item 6 (MÉDIO — PHP 5.6 fim de vida) — não migrado; nota de esforço registrada em 25/07/2026
  • [x] Item 7 (MÉDIO — webhook MP sem rate limit dedicado) — corrigido e validado em 25/07/2026
  • [~] Item 8 (MÉDIO — segredos dentro do webroot) — avaliado, não aplicado (ver justificativa)

1. CRÍTICO — Código-fonte de checkout/pagamento baixável publicamente via arquivos de backup

Achado: a regra do Nginx location ~* \.(log|sql|bak|backup|old|ini|sh)$ { deny all; } só bloqueia nomes que terminam exatamente em .bak. O padrão real de backup usado no projeto (arquivo.bkp_original_YYYYMMDD-HHMMSS_descricao, arquivo.bak_20251106, arquivo.bak2, arquivo.bak.2026-04-08-0244 etc.) não bate com essa regex e retornava HTTP 200.

Confirmado baixando ao vivo (antes da correção): mais de 150 arquivos, incluindo

checkout_pix.php.bkp_original_*, efetua-pagamento.php.bak_20260405,

confirm_pagamento.php.bak_1760505449, pedido.php.bkp_original_*,

webhook_mp_ingressos.php.bkp_original_2026-07-07_11-53-28 (webhook do Mercado Pago),

action.php.bkp_original_* (login do admin), entre outros.

Não havia segredo hardcoded nos arquivos verificados (tokens vêm de getenv()), mas a exposição do código de checkout/admin/webhook por completo facilita muito o trabalho de qualquer atacante.

Correção aplicada: nova location no vhost Nginx cobrindo .bak/.bkp em qualquer posição do nome (não só no final), mantendo os backups no lugar (não foram movidos, para não quebrar o workflow de versionamento local do projeto).

```nginx

location ~ \.(bak|bkp)([0-9_.-].)?$ {

deny all;

return 404;

}

```

Backup do arquivo mexido: /www/server/panel/vhost/nginx/rionoteatro.com.br.conf.bkp_original_20260724-1749_BK-341-fix-bak-exposure

Se o site cair depois desta mudança, restaurar esse .conf e rodar /www/server/nginx/sbin/nginx -t && /www/server/nginx/sbin/nginx -s reload.

Validado em 24/07/2026:

  • webhook_mp_ingressos.php.bkp_original_2026-07-07_11-53-28 → 404 (antes: 200)
  • checkout_pix.php.bkp_original_2026-04-27_23-00-hotfix-valor-mp → 404 (antes: 200)
  • efetua-pagamento.php.bak_20260405 → 404 (antes: 200)
  • action.php.bkp_original.20260410-0035 → 404 (antes: 200)
  • Home (/) → 200, sem regressão
  • Assets reais da home (/css/bootstrap.css, /css/theme.css, /admin/modulos/campanhas/tracking/utm_tracker.js) → 200, sem regressão
  • nginx -t sem erro antes do reload; reload aplicado sem downtime perceptível

Validação pós-fix: ver seção "Validação" no final deste documento.


2. ALTO — Painel /admin/ (login principal) sem proteção contra força bruta

O form de admin/login.php envia para admin/action.php. Não há limit_req no Nginx para /admin/ (diferente de /produtor/login.php e /produtor/action.php, que têm limit_req zone=login_rl), e admin/action.php não tem nenhuma lógica de tentativas/lockout. O painel de maior privilégio do sistema está, hoje, menos protegido que o painel de produtores.

Correção aplicada em 25/07/2026: adicionado location = /admin/action.php { limit_req zone=login_rl burst=5 nodelay; limit_req_status 429; ... } no vhost (mesma zona já usada em /produtor/). Lockout progressivo por usuário/IP na aplicação não foi implementado — fica como melhoria futura de código, fora do escopo desta correção de infra.

Backup: /www/server/panel/vhost/nginx/rionoteatro.com.br.conf.bkp_original_20260725-0944_BK-341-itens-2-4-5-7

Validado em 25/07/2026: 6ª requisição consecutiva a /admin/action.php já retorna 429; admin/login.php continua 200; guard de integridade do MP sem drift (a proteção é só de infra Nginx, não toca o arquivo action.php monitorado).


Set-Cookie: PHPSESSID=...; path=/ não tem nenhuma flag de proteção. Facilita roubo de sessão via XSS ou downgrade de conexão.

Correção aplicada em 25/07/2026: session.cookie_httponly=1 e session.cookie_secure=1 via .user.ini. PHP 5.6 não tem a diretiva nativa session.cookie_samesite (só existe desde PHP 7.3) — usado o truque padrão para versões antigas: session.cookie_path="/; SameSite=Lax" (o valor precisa estar entre aspas, senão o parser de INI corta tudo depois do ; como comentário — isso quebrou a primeira tentativa, corrigido antes do reload final). Depois de editar o .user.ini foi necessário systemctl restart php-fpm-56 (reload sozinho manteve o cache antigo do .user.ini nos workers).

Backup: /www/wwwroot/rionoteatro.com.br/.user.ini.bkp_original_20260725-0944_BK-341-item3-cookie-flags

Validado em 25/07/2026: Set-Cookie na home agora vem path=/; SameSite=Lax; secure; HttpOnly. Home e login continuam 200.


4. ALTO — Faltam headers de segurança básicos

Diferente do seuimovel.rio.br (que já tem X-Frame-Options, X-Content-Type-Options, Referrer-Policy via Django), o rionoteatro.com.br não envia nenhum desses headers.

Correção proposta: adicionar via add_header no vhost Nginx (mais rápido que alterar o PHP legado):

```nginx

add_header X-Frame-Options "SAMEORIGIN" always;

add_header X-Content-Type-Options "nosniff" always;

add_header Referrer-Policy "same-origin" always;

```

Correção aplicada em 25/07/2026, junto com o Strict-Transport-Security já existente. Backup: mesmo do item 2 (rionoteatro.com.br.conf.bkp_original_20260725-0944_BK-341-itens-2-4-5-7).

Validado em 25/07/2026: os três headers aparecem na resposta da home, sem regressão.


5. ALTO — TLS 1.1 habilitado

ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3; no vhost. TLS 1.1 está abaixo do mínimo exigido pelo PCI-DSS (TLS 1.2+, desde 2018) — relevante porque o site processa pagamento com cartão via Mercado Pago.

Correção aplicada em 25/07/2026: ssl_protocols TLSv1.2 TLSv1.3; (removido TLSv1.1). Backup: mesmo do item 2.

Validado em 25/07/2026: conexão forçando --tls-max 1.1 agora falha (sem handshake); --tlsv1.2 continua 200.


6. MÉDIO — PHP 5.6 em produção (fim de vida desde dez/2018)

Mais de 7 anos sem patch de segurança oficial do PHP core. Dívida técnica grande, migração é trabalho considerável dado o volume de código legado. Mapear esforço de migração para PHP 8.x como projeto à parte.

Nota de escopo registrada em 25/07/2026 (não migrado, decisão consciente): o codebase tem 11.143 arquivos .php, dos quais *120 ainda usam a extensão mysql_* (mysql_query/mysql_connect), removida por completo do PHP a partir da 7.0 — ou seja, não é só trocar a versão do binário, exige reescrever cada um desses pontos para mysqli_/PDO antes de qualquer upgrade, além de reteste completo de todo o fluxo de pagamento. Não há vendor/ (sem Composer instalado apesar de existir composer.json), o que sugere dependências geridas manualmente — mais um fator que aumenta o risco de regressão numa migração. Recomendação: tratar como projeto dedicado, com ambiente de staging e testes de regressão no fluxo de checkout/webhook antes de qualquer tentativa, não como parte de uma auditoria de segurança pontual.


7. MÉDIO — Webhook do Mercado Pago sem rate limiting dedicado

webhook_mp_ingressos.php já segue o padrão correto (não confia no corpo do POST — sempre revalida direto na API do MP com o token do comerciante antes de dar baixa em pedido, o que evita spoofing de notificação). Mas cada request faz uma chamada de rede síncrona à API do MP; um flood pode esgotar workers PHP-CGI ou disparar rate-limit da própria conta MP.

Correção aplicada em 25/07/2026: nova zona limit_req_zone $binary_remote_addr zone=mp_webhook_rl:10m rate=120r/m; em nginx.conf (mais generosa que login_rl/forms_rl porque webhook pode receber várias notificações legítimas em sequência durante picos de venda) e location = /webhook_mp_ingressos.php { limit_req zone=mp_webhook_rl burst=20 nodelay; ... } no vhost.

Backups: /www/server/nginx/conf/nginx.conf.bkp_original_20260725-0944_BK-341-item7-zone e o mesmo .conf.bkp_original_20260725-0944_BK-341-itens-2-4-5-7 do vhost.

Validado em 25/07/2026: webhook_mp_ingressos.php continua respondendo 200 em requisição isolada; guard de integridade do MP sem drift.


8. MÉDIO — Segredos dentro do webroot público (defesa em profundidade)

.env, config/connect.php etc. estão fisicamente dentro da pasta servida pelo Nginx. Hoje não são acessíveis (bloqueados por location ~ ^/(\.user.ini|\.htaccess|\.git|\.env|...)), mas essa proteção depende inteiramente da config atual continuar correta — como o item 1 provou, uma regra de bloqueio pode ter brechas não percebidas por anos.

Correção proposta (mais trabalhosa, não urgente): mover .env e configs sensíveis para fora do document root.

Avaliado em 25/07/2026 — decisão: não aplicar agora. Levantamento real do esforço: config/connect.php é referenciado por 122 arquivos com paths relativos inconsistentes ("config/connect.php", __DIR__ . '/config/connect.php' etc.), então mover essa pasta é alto risco. Mas o .env propriamente dito (onde ficam as credenciais) é lido em pelo menos 18 lugares diferentes do código, incluindo config/connect.php e vários módulos de admin/campanhas — e, mais importante, o guard de integridade do Mercado Pago (admin/cron/monitor_mercadopago_integrity.php) tem o caminho do .env hardcoded como $repo_root . '/.env' e usa esse arquivo tanto para hash quanto para comparar MERCADOPAGO_* no diff de drift — mover o arquivo sem atualizar o guard quebraria silenciosamente o próprio sistema que detecta comprometimento de credencial.

Recomendação: tratar como uma tarefa própria (não em execução não-supervisionada), com uma lista completa de todos os 18 pontos de leitura do .env + o guard, todos atualizados na mesma mudança, e teste de ponta a ponta do guard (--check/--seal) depois. Enquanto isso, a mitigação que já existe (bloqueio de dotfiles no Nginx, confirmado funcionando) permanece como única camada — vale relembrar que essa é a mesma categoria de proteção que falhou no item 1, então revisar essa regra de bloqueio periodicamente é prudente até esse item ser feito de verdade.


Validação

Cada item corrigido tem sua própria seção "Validado em ..." acima (itens 1, 2, 3, 4, 5 e 7).

Resumo do que foi verificado em produção depois das correções de 25/07/2026:

  • backups .bak/.bkp retornam 404 (antes 200); home, assets e /docs/ seguem 200;
  • 6ª requisição consecutiva a /admin/action.php retorna 429; admin/login.php segue 200;
  • Set-Cookie da home vem path=/; SameSite=Lax; secure; HttpOnly;
  • X-Frame-Options, X-Content-Type-Options e Referrer-Policy presentes na resposta da home;
  • handshake com --tls-max 1.1 falha; --tlsv1.2 retorna 200;
  • webhook_mp_ingressos.php responde 200 em requisição isolada;
  • guard de integridade do Mercado Pago sem drift depois de todas as mudanças (nenhum arquivo

monitorado foi alterado — as correções 2, 4, 5 e 7 são de infra Nginx, e o item 3 é .user.ini,

que não está na lista monitorada).

Itens 6 e 8 não têm validação porque não foram aplicados — ver o motivo em cada seção.