Voltar ao blog
PHPsegurançaOWASPLaraveldesenvolvimento web

Segurança em PHP: OWASP Top 10 na prática

Segurança é o assunto que todo desenvolvedor acha que sabe e poucos levam a sério até o dia que precisam.

Não é teoria. É padrão de comportamento que vi se repetir em projetos ao longo de anos: a equipe sabe que injeção existe, sabe que XSS existe, sabe do OWASP. Mas na prática o foco vai sempre pra funcionalidade, prazo, performance. Segurança entra depois. E “depois” às vezes é tarde demais.

Não vou passar pelo Top 10 inteiro como checklist, porque isso não é a forma mais útil de pensar sobre o assunto. Vou falar sobre o que realmente aparece em sistemas PHP, com frequência real, e o que resolve.

Injeção ainda está ali, em 2026

SQL injection devia ser coisa do passado. Não é.

Quem trabalha com Laravel e usa Eloquent ou Query Builder está razoavelmente protegido. O problema aparece quando alguém, por pressa ou por não saber, escreve uma query concatenando valores vindos do usuário diretamente na string. Já vi isso em sistema de médio porte, equipe razoável, código limpo em 90% do projeto. Uma tela de relatório desenvolvida às pressas pra uma demo, com filtro construído na mão. Ficou ali por meses, em produção, com dados reais.

A injeção não é só banco de dados. Command injection é a mesma classe de problema: código que passa input do usuário para funções que executam comandos no sistema sem sanitizar. Em PHP isso aparece com certa frequência em funcionalidades de geração de PDF, conversão de arquivo, qualquer coisa que por baixo chama uma ferramenta externa. Parece inofensivo até que não é.

Autenticação que parece certa mas não é

Implementar autenticação não é o problema. Implementar autenticação correta é.

A vulnerabilidade que mais aparece em revisão de código não é “sistema sem senha”. É sessão sem expiração adequada, token de recuperação válido por tempo demais, “lembrar de mim” que mantém o usuário logado indefinidamente com cookie que nunca muda.

Um ponto que quase sempre está errado em sistemas que não usam biblioteca estabelecida: o token de reset de senha. Se ele não tem prazo curto, se pode ser reutilizado, se não é invalidado imediatamente após o uso, você tem um vetor de ataque. Já vi sistema onde o link de reset de senha era válido por sete dias. Qualquer e-mail encaminhado, qualquer histórico de browser acessado por outra pessoa, e a conta estava comprometida.

Sinceramente, senha forte também é mais complicado do que parece. Não é sobre exigir maiúscula, número e símbolo especial. É sobre impedir senhas que aparecem em listas de vazamentos. É sobre rate limiting em tentativa de login. Em PHP isso não é difícil de implementar, mas precisa de intenção explícita. Ninguém coloca no backlog “implementar proteção contra force brute”.

XSS: o mais subestimado pelos devs backend

Desenvolvedores backend tendem a não levar XSS tão a sério quanto deveriam. “Isso é problema do frontend.” Não é, não.

Cross-site scripting aparece quando você renderiza conteúdo que o usuário inseriu sem escapar corretamente. Em Laravel, o Blade escapa por padrão com a sintaxe de duplas chaves. O problema surge nos lugares onde você usa a sintaxe sem escape pra conteúdo que “você controla”, e depois esse conteúdo começa a vir de um campo que o usuário preenche.

Aliás, tem dois tipos e a distinção importa. XSS reflexivo é passado na URL. XSS armazenado fica no banco e afeta qualquer usuário que carrega aquela página. O segundo é infinitamente mais perigoso porque não exige que a vítima clique em nenhum link suspeito. A brecha está lá, silenciosa, servida pelo próprio sistema.

Em projetos com editor de texto rico, essa vulnerabilidade é quase garantida se não houver sanitização no lado do servidor. Não confie no que o JavaScript do editor filtra. O JavaScript do editor pode ser bypassado por qualquer requisição direta à API.

IDOR: o buraco que aparece em auditoria

Insecure Direct Object Reference. O nome técnico para quando você acessa a fatura 12345 e consegue ver a fatura 12344 só de trocar o número na URL.

Esse é o que mais aparece em sistemas PHP que cresceram rápido. Não porque os desenvolvedores não sabem que autorização existe. É porque em algum momento o foco estava na velocidade de entrega, a checagem de “esse usuário pode ver esse recurso” ficou só no frontend, e ninguém revisou sistematicamente.

Prefiro verificar autorização o mais perto possível do dado, no model ou no service, não no controller. Controller pode ser chamado de lugares inesperados, testes unitários podem não passar pelo middleware. Verificação de autorização que fica em camada que pode ser pulada é verificação que vai ser pulada, cedo ou tarde.

Configuração insegura em produção

Esse item do OWASP é amplo, mas tem um padrão muito claro em PHP.

Debug mode ativado em produção. Já vi isso em sistema acessível publicamente, exibindo stack trace completo com variáveis de ambiente na tela. Toda a estrutura de diretórios, versão do PHP, bibliotecas instaladas, às vezes strings de conexão com banco. Um presente pra qualquer pessoa que queira entender a arquitetura do sistema sem pedir.

.env no repositório é clássico demais para mencionar, mas ainda aparece. Geralmente em projeto que começou simples, sem pipeline de CI/CD, com desenvolvedor solo que comitou tudo junto numa sexta de tarde. Chegou assim no repositório e nunca saiu.

Headers de segurança ausentes também entram aqui. Content Security Policy, X-Frame-Options, X-Content-Type-Options. Não são mágica, mas fecham vetores de ataque que de outra forma ficam abertos por padrão. Laravel facilita isso com middleware, mas alguém precisa colocar.

O que realmente fecha as brechas

Não é rodar um scanner automático. Scanner automático é bom pra achar o que está na superfície. As vulnerabilidades mais sérias que encontrei ao longo dos anos não eram as que um scanner ia detectar numa requisição GET simples.

Revisão de código com intenção de segurança é diferente de revisão normal. Você está procurando onde o dado do usuário entra no sistema, como ele se move pelas camadas, onde ele sai. É um exercício mental diferente de “esse código está correto e legível”. Você precisa partir do pressuposto que o usuário está tentando te prejudicar e ver se o código aguenta.

Manter dependências atualizadas é manutenção básica que poucas equipes fazem sistematicamente. O ecossistema PHP tem CVEs que aparecem, são corrigidos rapidamente, e ficam ali esperando os projetos que nunca rodaram o equivalente a uma atualização. Automatizar a verificação periódica, pelo menos um aviso quando houver vulnerabilidade conhecida numa versão instalada, é o mínimo.

E um ponto que raramente está nos planos de qualquer projeto: treinamento da equipe que vai manter o sistema. Uma vulnerabilidade pode ser introduzida por um desenvolvedor que entrou depois que o sistema foi auditado, que nunca ouviu falar de IDOR, que concatenou uma query porque foi mais rápido e a entrega era pra ontem.

Pois é. A maioria dessas vulnerabilidades não exige conhecimento especializado pra explorar. Exige saber onde procurar. E quem procura tem paciência pra isso.


Gabriel Schunck trabalha com sistemas PHP e Laravel há mais de 20 anos. Se você quer uma revisão de segurança no seu sistema antes de escalar ou de uma auditoria externa, entra em contato pelo gabriels.dev.br.

Falar no WhatsApp