Pular para o conteúdo
Voltar para o acervo
Engenharia7 min de leituraPasso 17 de 22

As vulnerabilidades que aparecem de verdade

A maior parte dos vazamentos que viram notícia não usa técnica sofisticada. Usa uma destas seis falhas, e as seis têm correção conhecida e barata.

· Gabriel Dias

Existe uma distância grande entre a segurança que aparece em conferência e a segurança que te protege. A primeira é sobre cadeia de exploração e técnica nova. A segunda é sobre um endpoint que não verificou se aquele usuário podia ver aquele registro.

Este artigo é sobre a segunda.

Antes das falhas: o que muda o jogo

Duas ideias que valem mais que qualquer ferramenta.

Superfície de ataque. Tudo por onde alguém pode entrar: cada endpoint, cada parâmetro, cada dependência, cada porta, cada pessoa com acesso. Reduzir superfície é a medida mais eficaz e mais barata que existe: endpoint que não existe não é explorado.

STRIDE, para pensar de forma sistemática: Spoofing (fingir ser outro), Tampering (alterar dado), Repudiation (negar que fez), Information disclosure (vazar), Denial of service (derrubar), Elevation of privilege (virar admin).

Passe qualquer funcionalidade por essas seis letras e você encontra coisas que não teria pensado. Leva quinze minutos.

1. Falha de autorização (IDOR)

Você troca o número na URL (/pedidos/1042 para /pedidos/1043) e vê o pedido de outra pessoa.

É a falha mais comum que existe. Não é sofisticada; um usuário curioso encontra por acidente.

A causa raiz é quase sempre a mesma: a autorização foi verificada na tela, não no servidor. O menu não mostra, o botão não aparece, e ninguém lembrou que a rota aceita qualquer id.

A regra, sem exceção: toda consulta filtra pelo dono.

Não é SELECT * FROM pedidos WHERE id = ?

É SELECT * FROM pedidos WHERE id = ? AND cliente_id = ?

Duas defesas extras: row-level security no banco, se ele suportar, garante a regra na camada de baixo mesmo que alguém esqueça na de cima. E identificador não sequencial (UUID, ULID) remove a descoberta acidental: é mitigação, não solução.

O primo: mass assignment. Você aceita o corpo inteiro da requisição e joga no objeto. O usuário manda "role": "admin" junto. Defesa: lista explícita dos campos que podem vir do cliente.

2. Injeção

A causa raiz é sempre a mesma: dado do usuário sendo interpretado como código.

Em SQL, a defesa é consulta parametrizada. Não é escapar string: é parametrizar, sempre. O banco recebe a estrutura da query e os valores separadamente, e valor nunca vira comando.

E o mesmo princípio vale para todo o resto: comando de sistema (use a forma que recebe lista de argumentos, nunca concatenação numa shell), template (nunca renderize template vindo do usuário), LDAP, XPath.

E hoje, prompt de modelo de linguagem, que é o mesmo problema numa roupa nova, com o agravante de não existir equivalente à consulta parametrizada. Volto nisso no fim.

3. XSS

Código do atacante rodando no navegador da vítima, com a sessão dela.

Defesa em camadas:

Escape na saída, conforme o contexto. HTML, atributo HTML, JavaScript e URL escapam de formas diferentes. Frameworks modernos fazem isso por padrão, e o perigo mora nas escapadas: dangerouslySetInnerHTML, v-html, template raw.

Content-Security-Policy. Limita de onde script pode vir. Uma CSP bem configurada transforma um XSS explorável em um XSS inofensivo. É a defesa com melhor retorno e a mais ignorada.

4. CSRF

O navegador da vítima faz uma requisição autenticada sem ela querer, porque o cookie vai junto automaticamente.

Defesa moderna: SameSite no cookie (Lax já resolve a maior parte; Strict é mais seguro e quebra alguns fluxos), mais token anti-CSRF em operações que mudam estado.

E note: se a sua API usa token no cabeçalho Authorization em vez de cookie, ela não é vulnerável a CSRF, porque o navegador não envia esse cabeçalho automaticamente. É um dos poucos argumentos técnicos reais a favor de token sobre cookie.

5. SSRF

Você faz o servidor buscar uma URL fornecida pelo usuário, e ele aponta para dentro da sua rede.

O alvo clássico em nuvem é o serviço de metadados, em 169.254.169.254, que devolve credenciais da instância. Foi exatamente assim que aconteceu o caso da Capital One, em 2019, com mais de cem milhões de registros expostos.

Defesas:

→ Lista de permissão de destinos, em vez de lista de bloqueio.

→ Bloquear faixas internas, e resolver o nome antes de validar, porque um domínio controlado pelo atacante pode apontar para IP interno.

→ Nas máquinas AWS, exigir IMDSv2, que usa token e não é acessível por requisição simples.

→ Timeout curto e sem seguir redirecionamento automaticamente.

Onde aparece sem você perceber: geração de PDF a partir de URL, importação de imagem por link, webhook configurável, pré-visualização de link.

6. Desserialização e upload

Desserialização insegura: transformar dado do usuário em objeto pode executar código, dependendo da biblioteca e da linguagem. Nunca desserialize formato binário vindo de fonte não confiável. Prefira JSON com esquema validado.

Upload de arquivo: valide o tipo pelo conteúdo, não pela extensão nem pelo Content-Type. Guarde fora do diretório servido pelo servidor web. Sirva de um domínio separado, para que um HTML malicioso enviado não rode no domínio da sua aplicação. Limite tamanho.

  1. Autorização (IDOR)a mais comumTrocar o id na URL e ver o registro de outro. Toda consulta filtra pelo dono, sem exceção.
  2. Injeçãodado vira códigoConsulta parametrizada, sempre. Vale para SQL, shell, template, LDAP e prompt.
  3. XSScódigo na vítimaEscape por contexto na saída. Uma CSP bem posta transforma XSS explorável em inofensivo.
  4. CSRFo cookie vai juntoSameSite mais token anti-CSRF. API com token no cabeçalho não é vulnerável.
  5. SSRFo servidor buscaLista de permissão, bloquear faixas internas, IMDSv2. Foi o caso da Capital One.
  6. Desserialização e uploadobjeto e arquivoNunca desserialize binário não confiável. Valide o upload pelo conteúdo e sirva de outro domínio.
Nenhuma delas é técnica sofisticada. Todas têm correção conhecida e barata.

As três coisas que valem mais que as seis

Segredos. Não vão no repositório, nem em variável de ambiente que aparece em log, nem no Dockerfile. Vão num cofre, com rotação. Rode um scanner tipo gitleaks no pipeline: ele acha o que já vazou. E se vazou, a única resposta é rotacionar: apagar do histórico do git não adianta, alguém já clonou.

Cadeia de suprimentos. As suas dependências são código de estranhos rodando com os seus privilégios. Fixe versões, use lockfile, gere inventário de componentes, escaneie por vulnerabilidade conhecida. O incidente do xz-utils em 2024 (um mantenedor cultivado por dois anos para inserir uma porta dos fundos) mostra o limite das ferramentas, mas versão fixada e build reproduzível limitam o estrago.

Menor privilégio. Na nuvem, no banco, no contêiner. A pergunta a fazer em toda revisão: se este componente for comprometido, o que o atacante consegue fazer? Se a resposta for "tudo", o problema não é a vulnerabilidade: é o desenho.

Prompt injection: a nova da lista

Vale um parágrafo porque muda o cálculo de risco de qualquer sistema com IA.

A causa raiz é a mesma da injeção de SQL: instrução e dado no mesmo canal. A diferença é que não existe consulta parametrizada para linguagem natural. Não há solução completa hoje.

E a variante perigosa é a indireta: o conteúdo malicioso está num documento que o seu RAG recupera, numa página que o agente lê. O atacante nunca falou com o seu sistema.

O que ajuda: delimitar o conteúdo não confiável, dar o mínimo de privilégio à ferramenta, exigir confirmação humana para ação irreversível, validar a saída com código, e limitar o alcance da ação.

A regra mental: trate a saída do modelo como entrada de usuário não confiável.

O exercício de uma hora

Junte três pessoas:

10 min: desenhe o fluxo de dados da funcionalidade, marcando as fronteiras de confiança.

30 min: passe cada fronteira pelo STRIDE, anotando tudo sem filtrar.

15 min: ordene por probabilidade vezes impacto.

5 min: escolha as três primeiras e crie tarefas com dono.

Não precisa de ferramenta nem de consultor, e pega mais coisa do que qualquer varredura automática.

Leia depois disto

Fala comigo

Dúvida sobre o artigo? Me chama no WhatsApp

Sem formulário e sem lista de e-mail. Se você discorda de alguma coisa que eu escrevi, ou quer contar como resolveu aí, a conversa é direta comigo.

Abrir conversa