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-254-hardening-cadastro-palcofan-abuso-automatizado.md • 2026-04-11T09:11:34.624Z

BK-254 - Hardening do cadastro público e PalcoFan contra abuso automatizado

Contexto

Em 2026-04-11, o site recebeu automação hostil a partir do IP 148.113.214.92, com payloads clássicos de SQLi (DBMS_PIPE, PG_SLEEP, waitfor delay) espalhados por formulários e URLs.

Achado operacional confirmado:

  • conta falsa criada em clientes.id = 50981
  • nome: MmzHrrdb
  • e-mail: sample@email.tst
  • cpf: g00dPa$$w0rD
  • rg: 1
  • status: A
  • essa conta foi usada para enviar avaliações pendentes no PalcoFan, inclusive para:
  • teatro id 118
  • evento id 1460
  • peca id 1493

Leitura atual:

  • até aqui, não há prova de webshell nem de comprometimento confirmado do servidor
  • há prova forte de abuso da aplicação por falta de barreiras no cadastro público e no formulário AJAX do PalcoFan

Evidências

Conta falsa no banco

```sql

SELECT id,nome,email,created,telefone,celular,cpf,rg,status

FROM clientes

WHERE id = 50981;

```

Retorno observado:

```json

{"id":"50981","nome":"MmzHrrdb","email":"sample@email.tst","created":"2026-04-11 02:08:36","telefone":null,"celular":"(1","cpf":"g00dPa$$w0rD","rg":"1","status":"A"}

```

Comentários maliciosos armazenados como texto

```sql

SELECT id,id_cliente,tipo_item,id_item,estrelas,comentario,status,data_criacao

FROM tb_avaliacoes

WHERE comentario LIKE '%DBMS_PIPE.RECEIVE_MESSAGE%';

```

Retornos observados:

  • id=5, id_cliente=50981, tipo_item=teatro, id_item=118
  • id=4, id_cliente=50981, tipo_item=evento, id_item=1460
  • id=2, id_cliente=50981, tipo_item=peca, id_item=1493

Logs web

O access log mostrou rajadas do mesmo IP atacando:

  • painel/modulos/profile/index.php?act=editar
  • produtor/modulos/profile/?act=editar
  • produtor/modulos/eventos/incluir.php?act=cadastrar

com payloads de:

  • DBMS_PIPE.RECEIVE_MESSAGE(...)
  • PG_SLEEP(...)
  • waitfor delay
  • variantes OR 1=1

Causa raiz confirmada

Cadastro público frouxo

Em action.php, o case "cadastro" aceitava qualquer valor não vazio como “passaporte” quando o campo cpf não tinha 11 dígitos:

```php

$cpf_valido = (strlen($CPF) == 11) ? valida_cpf($CPF) : (strlen($CPF) > 0);

```

Isso permitiu criar conta com cpf = g00dPa$$w0rD.

PalcoFan sem barreiras reais

Em includes/ajax_palcofan.php, o endpoint:

  • exigia login
  • mas não tinha CSRF
  • não tinha honeypot
  • não tinha rate limit
  • não tinha bloqueio mínimo de conteúdo abusivo

Objetivo do hotfix

  1. endurecer cadastro público
  2. endurecer o PalcoFan
  3. reduzir abuso automatizado sem quebrar o fluxo legítimo
  4. registrar que o incidente atual é de abuso do app, não de RCE comprovado

Escopo de código desta rodada

  • config/security_request_helper.php
  • action.php
  • cadastre-se.php
  • includes/inc_palcofan.php
  • includes/ajax_palcofan.php

Correções mínimas planejadas

Cadastro público

  • validar e-mail no servidor
  • validar confirmação de e-mail no servidor
  • exigir senha mínima
  • validar CPF brasileiro real quando vier com 11 dígitos
  • validar “passaporte/documento alternativo” com regex mínima segura
  • validar rg/documento com foto com regex mínima segura
  • adicionar CSRF
  • adicionar honeypot
  • adicionar rate limit por IP

PalcoFan

  • adicionar CSRF
  • adicionar honeypot
  • adicionar rate limit
  • limitar tamanho de comentário
  • rejeitar payloads abusivos típicos de SQLi no campo de comentário

Implementado nesta rodada

Helper novo

  • config/security_request_helper.php
  • token CSRF por escopo
  • honeypot
  • detecção simples de IP
  • rate limit em arquivo temporário
  • validação mínima de CPF/passaporte
  • validação mínima de documento com foto
  • assinatura simples de payloads clássicos de SQLi

Cadastro público endurecido

  • action.php
  • passou a validar csrf_token
  • passou a validar honeypot website
  • ganhou rate limit por IP
  • passou a validar e-mail e confirmação de e-mail no servidor
  • passou a exigir senha mínima
  • deixou de aceitar qualquer string arbitrária como “passaporte”
  • passou a validar o campo de documento com foto antes de inserir em clientes
  • cadastre-se.php
  • formulário agora envia csrf_token
  • formulário agora inclui honeypot invisível

PalcoFan endurecido

  • includes/inc_palcofan.php
  • formulário agora envia csrf_token
  • formulário agora inclui honeypot invisível
  • includes/ajax_palcofan.php
  • valida csrf_token
  • valida honeypot
  • aplica rate limit por cliente/IP
  • limita comentário a 1000 caracteres
  • bloqueia payloads com assinatura clássica de SQLi antes de gravar

Validação local executada

  • php -l config/security_request_helper.php
  • php -l action.php
  • php -l cadastre-se.php
  • php -l includes/inc_palcofan.php
  • php -l includes/ajax_palcofan.php

Validação funcional auxiliar:

  • regex de passaporte aceitou A1234567
  • regex de passaporte rejeitou g00dPa$$w0rD
  • regex de documento rejeitou 1'||DBMS_PIPE
  • filtro de assinatura abusiva detectou DBMS_PIPE.RECEIVE_MESSAGE(...)

Próximos passos fora deste hotfix

  • endurecer endpoints que ainda aceitam mutação por GET
  • revisar páginas de perfil cliente/produtor que apareceram nos logs de abuso
  • avaliar bloqueio temporário do IP 148.113.214.92 na borda
  • revisar política de ativação automática de conta pública
  • decidir o tratamento da conta 50981 e das avaliações pendentes já gravadas

Revisão das recomendações externas recebidas em 2026-04-11

1. Desabilitar display_errors e manter log_errors

Status:

  • válido
  • já aplicado no projeto

Leitura:

  • o relatório acertou ao apontar o vazamento de path real do servidor
  • isso foi mitigado em duas camadas:
  • hotfix funcional do urlbase em includes/inc_peca.php
  • display_errors=Off no php.ini local e no .user.ini

Observação:

  • o follow-up de error_log dedicado e expose_php fica documentado em BK-255

2. includes/security.php com PDO + prepared statements + CSRF + rate limit

Status:

  • válido como direção
  • não válido como drop-in literal

Leitura:

  • a parte conceitual está correta:
  • prepared statements
  • CSRF
  • rate limit
  • mas o snippet proposto é genérico demais para o RNT:
  • o projeto hoje é legado em mysqli/helpers próprios
  • trocar para PDO em massa no meio do incidente aumentaria risco
  • Input::text() com htmlspecialchars() no momento da entrada não deve virar padrão global do banco; o correto continua sendo escapar na saída

Decisão desta rodada:

  • em vez de importar esse arquivo cru, foi criado config/security_request_helper.php
  • ele cobre o recorte urgente do incidente sem refatoração transversal do banco inteiro

3. Snippet de Nginx com fastcgi_pass e rate limit

Status:

  • parcialmente válido
  • perigoso se aplicado cru

Leitura:

  • válido:
  • headers HTTP de segurança
  • limit_req_zone
  • bloqueio de arquivos sensíveis
  • perigoso/incorreto para o ambiente real:
  • o snippet usa php-cgi-74.sock, mas o RNT hoje mostra php-cgi-56.sock nos logs
  • sobrescrever fastcgi_pass manualmente no vhost do aaPanel sem reconciliar com o include atual pode quebrar o site
  • as rotas listadas não cobrem o vetor confirmado do incidente (/includes/ajax_palcofan.php, /action.php, painel/action.php, produtor/.../action.php)
  • bloquear curl/7. como user-agent é agressivo demais e pode derrubar integrações legítimas
  • X-XSS-Protection é legado/obsoleto e não deve ser tratado como defesa principal

Decisão:

  • esse tema foi separado para BK-255

4. reCAPTCHA v3

Status:

  • válido como camada adicional
  • não substitui validação, CSRF e rate limit

Leitura:

  • bom candidato para:
  • cadastro público
  • login
  • comentário/avaliação
  • precisa:
  • chave em local seguro
  • score ajustado com teste real
  • fallback para falsos positivos

Decisão:

  • manter como follow-up prioritário de segurança de aplicação

5. Cloudflare / WAF

Status:

  • válido

Leitura:

  • útil para filtrar scanners óbvios e dar rate limit na borda
  • não elimina a necessidade de corrigir o app

Decisão:

  • manter como follow-up de borda em BK-255

6. Ideia de usar “Conta WhatsApp Ativa” como sinal de usuário real

Status:

  • válido como sinal de confiança
  • não válido como único fator de autenticação/autorização

Leitura:

  • isso pode ajudar muito como antifraude para áreas de abuso, por exemplo:
  • comentar no PalcoFan
  • abrir certas funções de produtor
  • reduzir spam de conta recém-criada
  • mas não deve virar bloqueio bruto de “acessar a área” inteira, porque:
  • depende de um serviço externo
  • pode excluir usuário legítimo sem WhatsApp ativo
  • não substitui sessão, senha, CSRF e rate limit

Recomendação prática:

  • usar como trust score
  • melhor ainda: combinar com evidência de compra real

Sugestão de regra futura para o PalcoFan:

  • permitir avaliação se o cliente cumprir ao menos um dos critérios:
  • tem pedido pago/consumido relacionado
  • tem telefone com sinal forte de conta WhatsApp ativa
  • foi liberado manualmente pelo admin

Isso é mais coerente com o produto do que deixar qualquer conta recém-criada comentar só por estar logada.

7. Hipótese de IDOR em checkout_pix.php?id=...

Status:

  • não confirmado como IDOR explorável no código atual
  • válido como preocupação de enumeração/tokenização futura

Leitura:

  • o checkout_pix.php hoje ainda usa ID sequencial na URL
  • porém o código já faz ownership guard por sessão:
  • pedidos.cliente_id == $_SESSION['CMS_X_Cliente']['id']
  • orders.user_id == $_SESSION['CMS_X_Cliente']['id']
  • os endpoints críticos de PIX/carteira/cartão em action.php também filtram pelo cliente_id da sessão

Conclusão:

  • a crítica “URL sequencial” é válida
  • a crítica “IDOR confirmado do pedido de outro cliente” não ficou confirmada no código atual
  • isso virou follow-up próprio no BK-257