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)
- BK-136
- BK-137
- BK-138
- BK-147
- BK-148
- BK-149
- BK-150
- BK-151
- BK-156
- BK-158
- BK-159
- BK-160
- BK-161
- BK-162
- BK-163
- BK-164
- BK-165
- BK-166
- BK-170
- BK-171
- BK-172
- BK-177
- BK-183
- BK-186
- BK-187
- BK-189
- BK-190
- BK-191
- BK-192
- BK-193
- BK-195
- BK-196
- BK-197
- BK-198
- BK-199
- BK-201
- BK-205
- BK-207
- BK-208
- BK-209
- BK-210
- BK-211
- BK-212
- BK-213
- BK-214
- BK-215
- BK-216
- BK-217
- BK-218
- BK-219
- BK-220
- BK-221
- BK-229
- BK-230
- BK-231
- BK-232
- BK-233
- BK-234
- BK-235
- BK-236
- BK-239
- BK-240
- BK-241
- BK-242
- BK-243
- BK-244
- BK-245
- BK-246
- BK-248
- BK-249
- BK-250
- BK-251
- BK-252
- BK-253
- BK-254
- BK-255
- BK-256
- BK-257
- BK-258
- BK-259
- BK-260
- BK-261
- BK-262
- BK-263
- BK-264
- BK-265
- BK-266
- BK-267
- BK-268
- BK-269
- BK-270
- BK-271
- BK-272
- BK-275
- BK-276
- BK-277
- BK-278
- BK-279
- BK-280
- BK-295
- BK-313
- BK-341
- BK-345
- BK-346
Detalhe do BK Selecionado
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 -tsem 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).
3. ALTO — Cookie de sessão sem HttpOnly/Secure/SameSite
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/.bkpretornam404(antes200); home, assets e/docs/seguem200; - 6ª requisição consecutiva a
/admin/action.phpretorna429;admin/login.phpsegue200; Set-Cookieda home vempath=/; SameSite=Lax; secure; HttpOnly;X-Frame-Options,X-Content-Type-OptionseReferrer-Policypresentes na resposta da home;- handshake com
--tls-max 1.1falha;--tlsv1.2retorna200; webhook_mp_ingressos.phpresponde200em 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.