Skip to content
This page has been auto-translated and may contain errors.View in English

Modelagem de ameaças baseada em funcionalidades

Um portal de estudantes ganha uma nova funcionalidade de upload. Os estudantes podem enviar tarefas, e os professores podem deixar feedback.

Isso parece pequeno o suficiente para construir. Um formulário, um campo de arquivo, um botão de envio, uma página para o professor.

Também é pequeno o suficiente para modelar as ameaças de forma adequada.

A modelagem de ameaças baseada em funcionalidades pega uma funcionalidade e a percorre do início ao fim. A cada etapa, você pergunta o que pode dar errado e o que o código precisa verificar.

Percorra a funcionalidade

Comece com a história normal:

  1. Um estudante faz login.
  2. O estudante envia um arquivo.
  3. O servidor o armazena.
  4. Um professor abre o envio.
  5. O professor deixa um feedback.
  6. O estudante lê o feedback.

Essa lista é o mapa. Você não precisa de um diagrama sofisticado para começar.

Agora marque os pontos em que um valor cruza um limite de confiança:

EtapaValor que cruza o limiteO que perguntar
UploadNome, tipo e tamanho do arquivoO servidor verificou o próprio arquivo?
ArmazenamentoCaminho e metadadosUm estudante pode sobrescrever o arquivo de outro?
Visão do professorId do envioEsse professor está de fato atribuído a esse estudante?
FeedbackTexto do feedbackEle pode virar script quando exibido?
Visão do estudanteId do feedbackUm estudante pode ler o feedback de outro estudante?

Agora a funcionalidade tem forma. Você consegue ver onde as decisões de segurança se encaixam.

Comece pela história, depois adicione as ameaças

Se você começa pelos nomes das ameaças, o exercício parece abstrato.

Se você começa pela história da funcionalidade, cada ameaça tem onde se encaixar.

JunoPercorra a funcionalidade Comece com a história normal. Quem faz login, o que essa pessoa envia, para onde isso vai, quem lê depois?

Depois marque os momentos em que seu aplicativo recebe algo que ele não escolheu. Esses são os pontos em que o servidor precisa fazer mais perguntas.

JunoPercorra a funcionalidade Na prática, o melhor caminho é transformar a funcionalidade em linhas de tabela. Etapa, valor, limite, verificação. Esse formato mantém o modelo próximo do código.

Na funcionalidade de upload, os pontos mais sensíveis são o próprio arquivo, o caminho armazenado, o id do envio, o feedback do professor e a visão do estudante. Cada um deles corresponde a um handler ou a uma decisão de armazenamento que você pode testar.

JunoPercorra a funcionalidade Modelos por funcionalidade funcionam porque são pequenos o suficiente para serem concluídos. A contrapartida é que eles herdam qualquer problema estrutural que o sistema já tenha.

Se toda funcionalidade depende do mesmo modelo de papéis frágil, você vai continuar encontrando a mesma ameaça com roupas diferentes.

É nesse ponto que o modelo da funcionalidade já cumpriu seu papel e está te avisando que é hora de agendar uma varredura mais ampla do sistema. Chato, sim. Mais barato do que fingir que o quinto achado duplicado é uma informação nova.

Transforme ameaças em verificações

Um modelo de funcionalidade não deveria terminar como uma lista de preocupações.

Para a funcionalidade de upload, uma preocupação poderia ser:

Um estudante poderia enviar algo inseguro.

Isso é verdade, mas é vago demais para servir de base. Transforme isso em uma verificação:

  • Limite o tamanho do arquivo antes de armazená-lo.
  • Permita apenas os tipos de arquivo esperados.
  • Gere o nome do arquivo armazenado no servidor.
  • Armazene os arquivos fora do diretório público do aplicativo.
  • Verifique se o professor está atribuído ao estudante antes de exibir o arquivo.

Agora o modelo pode virar critérios de aceite.

Uma ameaça se torna útil quando o próximo desenvolvedor consegue transformá-la em código ou em um teste.

JunoTransforme ameaças em verificações Uma preocupação diz o que te assusta. Uma verificação diz o que o aplicativo vai fazer a respeito.

"Upload inseguro" é uma preocupação. "Limitar o tamanho do arquivo e gerar o nome do arquivo armazenado no servidor" é uma verificação que alguém consegue construir.

JunoTransforme ameaças em verificações Escreva as verificações na mesma linguagem do ticket. Isso mantém o modelo vivo depois da reunião.

Por exemplo: o professor só pode ver um envio quando o servidor confirma que esse professor está atribuído àquele estudante. Essa frase vira uma verificação de rota e um caso de teste sem precisar de tradução.

JunoTransforme ameaças em verificações A verificação precisa estar exatamente onde a decisão é tomada. Um botão desabilitado na interface do professor até ajuda, mas não é o controle. A rota que serve o arquivo é o controle.

É aí que sistemas antigos ficam caros. Uma funcionalidade pode ter três caminhos para o mesmo dado: a rota web, a ferramenta de administração e a exportação em segundo plano. Se a verificação existir em apenas um desses caminhos, o modelo encontrou uma porta e a implementação construiu uma cortina.

Experimente com o feedback do professor

Agora use o mesmo método por conta própria.

A funcionalidade diz: professores podem deixar feedback nos envios dos estudantes.

Responda às cinco perguntas baseadas em funcionalidade antes de continuar lendo.

  1. Quem envia o valor?
  2. Quem lê esse valor depois?
  3. Qual decisão importa?
  4. O que pode dar errado?
  5. O que o código deveria verificar?
Compare com suas respostas
PerguntaUma resposta razoável
Quem envia o valor?O professor envia o texto do feedback.
Quem lê esse valor depois?O estudante, e possivelmente outro professor.
Qual decisão importa?Só um professor atribuído pode deixar feedback.
O que pode dar errado?O feedback pode conter script, ou cair no envio errado.
O que o código deveria verificar?A atribuição no servidor, o tamanho do texto e a exibição segura na hora de renderizar.

A pergunta 2 é a que carrega mais peso e recebe menos atenção. Identificar quem vai ler um valor depois é o que revela que ele será renderizado em uma página, e é isso que torna "pode conter script" uma pergunta que vale a pena fazer.

Responda só a pergunta 1 e você tem validação de entrada. Responda também a pergunta 2 e você tem segurança de saída também.

A correção exata vem mais adiante no manual. O que importa agora é o hábito: percorra a funcionalidade, marque o limite, escreva a verificação. É esse o método inteiro.

O front-end pode orientar, mas quem decide é o servidor

A página pode esconder os controles de feedback dos professores que não estão atribuídos.

Mesmo assim, a rota precisa verificar a atribuição, porque qualquer pessoa pode chamar a rota diretamente.

JunoExperimente com o feedback do professor O feedback do professor parece só um texto numa caixa, mas a funcionalidade tem várias decisões escondidas dentro dela.

Quem pode escrever? A qual envio ele pertence? Quem pode ler depois? Pensar em segurança é perceber essas decisões antes que o código as responda silenciosamente por você.

JunoExperimente com o feedback do professor O feedback tem dois formatos comuns de bug: a pessoa errada consegue escrevê-lo, ou o texto certo se torna inseguro quando exibido depois.

Isso te dá duas verificações em lugares diferentes. A autorização pertence à rota que salva o feedback. A exibição segura pertence ao lugar onde o feedback é renderizado. Mesmo valor, destino diferente, regra diferente.

JunoExperimente com o feedback do professor Texto armazenado é paciente. Ele pode ficar quieto no banco de dados por meses e só se tornar perigoso quando uma nova página o renderiza em um contexto diferente.

É por isso que os modelos de funcionalidade deveriam nomear destinos, não só entradas. "O texto do feedback é exibido para estudantes e professores" é mais útil do que "o texto do feedback é armazenado". A segunda frase diz onde o dado dorme. A primeira diz onde ele pode acordar e estragar sua tarde.

Para onde isso vai a seguir

A modelagem de ameaças baseada em funcionalidades é a versão do dia a dia do STRIDE. Você pode aplicá-la dentro do planejamento, escrever as verificações no ticket e testá-las antes de a funcionalidade ir para produção.

A seguir, OWASP e bugs reais muda a linha do tempo. Em vez de perguntar o que pode dar errado antes do lançamento, ele dá nomes às coisas que já deram errado em aplicativos reais.