Falso positivo de segurança e a otimização que piora
Três achados que parecem graves e não são, e três "otimizações" que deixam o código pior — com o critério para separar em cada caso.
Aceitar um falso positivo custa caro de um jeito silencioso: você muda código que estava certo, adiciona complexidade sem motivo e treina o time a acreditar em achados sem evidência.
- Reconhecer os falsos positivos mais comuns em segurança.
- Exigir medição antes de aceitar sugestão de performance.
- Responder a um achado com evidência em vez de obediência.
Três falsos positivos clássicos de segurança
| O achado | Por que costuma ser falso | O que confirma de verdade |
|---|---|---|
| "Injeção de SQL" em query com nome de coluna dinâmico | Se a coluna vem de uma lista fechada no código, não há entrada não confiável | Rastrear a origem do valor até o request |
| "Uso de MD5 é inseguro" | MD5 para checksum de arquivo ou chave de cache não é uso criptográfico | Ver se o valor protege algo ou só identifica |
| "XSS" em template que já escapa por padrão | Vários motores escapam automaticamente; o achado ignora isso | Testar com payload real no ambiente |
BLOQUEANTE — Injeção de SQL em ordenacao(): $sql .= " ORDER BY $coluna $direcao"; Variável concatenada diretamente na query.
Parece grave e é um padrão que realmente costuma ser grave.
const COLUNAS = ['nome', 'criado_em', 'valor'];
$coluna = in_array($req['ordenar'], COLUNAS, true)
? $req['ordenar'] : 'criado_em';
$direcao = strtoupper($req['dir']) === 'ASC' ? 'ASC' : 'DESC';
$sql .= " ORDER BY $coluna $direcao";O valor só pode ser um de quatro literais definidos no código. Não há caminho da entrada do usuário até a query.
A diferença: O achado olhou a linha; o risco depende das três linhas anteriores. É o limite estrutural de revisar por trecho: quem revisa precisa rastrear a origem do valor, e é isso que o pedido da aula anterior chama de "cenário concreto de falha".
No exemplo acima, o código é seguro e ainda assim melhoraria com a lista de colunas e a ordenação centralizadas — porque a próxima pessoa que mexer pode não repetir a validação.
Recusar o achado como bloqueante e aceitá-lo como sugestão de manutenção é uma resposta melhor que qualquer um dos extremos.
Três otimizações que pioram
CREATE INDEX idx_status ON pedidos(status);
A coluna tem 3 valores distintos em 8 milhões de linhas. O otimizador vai ignorar o índice, e você paga escrita mais lenta e espaço em disco por nada.
EXPLAIN SELECT ... WHERE status = 'pendente' AND criado_em > ?; -- Se o filtro real combina status com data, o índice útil -- é composto, na ordem em que a query filtra: CREATE INDEX idx_status_data ON pedidos(status, criado_em);
Índice que o otimizador realmente usa, escolhido a partir da query real e não do nome da coluna no WHERE.
A diferença: Sugestão de índice sem EXPLAIN é palpite. Índice tem custo permanente de escrita — aceitar um que não é usado é piorar o sistema com aparência de melhoria.
- Micro-otimização que troca clareza por nada: substituir um laço legível por uma expressão encadeada de três níveis que roda 2% mais rápido em código que executa dez vezes por dia.
- Cache adicionado sem política de invalidação: resolve a lentidão hoje e cria um bug de dado velho na semana que vem, que é muito mais caro de diagnosticar.
- Paralelização sem medir onde está o tempo: se 90% do tempo é uma query, paralelizar a formatação da resposta não muda nada além do risco.
Você reportou este achado: [cole o achado] Antes de eu aceitar, responda: 1) Qual é o caminho completo do dado não confiável até o ponto vulnerável? Cite cada linha do trecho abaixo que faz parte desse caminho. 2) Escreva a entrada exata que exploraria isso. 3) O que no código impede essa entrada de chegar lá? Se nada impede, mostre. 4) Se for performance: qual medição sustenta a sugestão e qual seria o ganho estimado em números? Se você não conseguir responder 1 e 2 com precisão, retire o achado. Código completo do contexto: [cole as funções envolvidas, não só a linha]
Colar o contexto completo é metade da solução: a maioria dos falsos positivos de segurança vem de revisar uma linha sem ver a validação que está três linhas acima.
Quando achados são aceitos sem verificação, duas coisas acontecem juntas. O código acumula complexidade defensiva desnecessária. E as pessoas param de distinguir achado real de ruído — o que faz um achado grave passar despercebido no meio de vinte irrelevantes.
A regra que sustenta isso: nenhum achado vira mudança sem cenário concreto de falha ou medição. Vale para achado de ferramenta, de IA e de colega.
Como perceber: Alguém no time diz "melhor mudar, vai que" sobre um achado que ninguém conseguiu reproduzir.
- Todo achado de segurança tem o caminho do dado rastreado até a origem.
- Existe uma entrada concreta que exploraria a falha.
- Toda sugestão de performance tem medição antes e estimativa de ganho.
- Nenhum índice foi criado sem
EXPLAIN. - Nenhum cache foi adicionado sem política de invalidação escrita.
- Sem cenário reproduzível ou medição, um achado é hipótese — e hipótese não vira commit.
Comentários e dúvidas
Inscreva-se grátis para comentar, tirar dúvidas, marcar seu progresso e emitir o certificado ao fim do curso.
Inscrever-se grátis com GoogleAinda não há comentários nesta aula.