Ameaças e risco
Modelagem de ameaças com STRIDE, superfície de ataque, fronteiras de confiança e de segurança, gestão de risco e políticas.
Modelar ameaças é responder quatro perguntas, nesta ordem: o que estamos construindo, o que pode dar errado, o que vamos fazer, e fizemos um bom trabalho? Pular a primeira é o erro mais comum — sem o desenho do sistema, a lista de ameaças vira uma lista de medos.
STRIDE#
Seis categorias que cobrem praticamente tudo o que se faz contra um sistema. O valor delas é serem exaustivas o bastante para a reunião terminar.
| A ameaça | A propriedade que ela viola | A resposta aqui | |
|---|---|---|---|
| Spoofing | fingir ser outro | autenticação | hash_password com scrypt, TOTP, token assinado |
| Tampering | alterar dado em trânsito ou em repouso | integridade | AEAD, HMAC, Seg.auditoria |
| Repudiation | negar ter feito | não-repúdio | trilha encadeada — e a ressalva sobre chave simétrica |
| Information disclosure | ver o que não devia | confidencialidade | Seg.segredo, redigir, mascarar_pii |
| Denial of service | impedir o uso legítimo | disponibilidade | limitador, json_seguro, limite de corpo |
| Elevation of privilege | virar admin sem ser | autorização | RBAC por recurso, Arcane.Capacidade |
Superfície de ataque#
É a soma de todos os pontos por onde um dado de fora entra no sistema. Reduzi-la é a única medida que melhora todas as outras ao mesmo tempo — o que não existe não pode ser atacado.
| Ponto de entrada | O que costuma escapar | A peça |
|---|---|---|
| parâmetro de rota e query | faixa não conferida, tipo assumido | Seg.numero_seguro |
| corpo do pedido | JSON fundo demais, corpo gigante | Seg.json_seguro, Kiln.limite_de_corpo |
| cabeçalho | Host e X-Forwarded-For tratados como verdade | conferir contra uma lista |
| upload | nome com .., extensão, tamanho | Kiln.salvar_upload, Seg.nome_de_arquivo_seguro |
| URL fornecida pelo usuário | SSRF para a rede interna | Seg.url_segura |
| redirecionamento | ?proximo= para fora do site | Seg.redirecionamento_seguro |
| arquivo de configuração | segredo commitado | dataforge seguranca |
| dependência | pacote trocado numa versão publicada | forge.lock com sha256 |
adopt Arcane.Seguranca as Seg
// A superficie de uma rota, em quatro linhas. Cada uma fecha um
// ponto que um pedido de fora alcanca.
action listar(query):
pagina := Seg.numero_seguro(query["pagina"] ?? "1", 1, 10000)
por_pagina := Seg.numero_seguro(query["tamanho"] ?? "20", 1, 100)
busca := Seg.sem_controle(query["q"] ?? "")
yield {"pagina": pagina, "tamanho": por_pagina, "busca": busca}
assert listar({"pagina": "3"})["pagina"] is 3
assert listar({})["tamanho"] is 20
// '?tamanho=999999999' derruba a listagem, e passa por qualquer
// conversao que nao confira a faixa.
monitor:
listar({"tamanho": "999999999"})
assert no
handle UnsafeInputError as e:
out "recusado antes de chegar ao banco"Fronteira de confiança, fronteira de segurança#
São conceitos diferentes e a confusão entre eles custa caro. Uma fronteira de confiança é onde o nível de confiança muda — o dado atravessa e passa a ser suspeito. Uma fronteira de segurança é onde existe um mecanismo que obriga a separação.
| Fronteira | Tipo | O que ela garante |
|---|---|---|
| navegador → servidor | confiança e segurança | processos e máquinas diferentes |
| processo → processo | ambas | o sistema operacional isola a memória |
Arcane.Capacidade | só de confiança | recusa o adopt; não tira o que já foi entregue |
| thread → thread | nenhuma | memória compartilhada; nada isola |
| validação de entrada | só de confiança | depende de quem escreveu chamar a função |
Gestão de risco#
Risco é probabilidade × impacto, e o ponto de fazer a conta é ordenar — não há orçamento para tratar tudo. As quatro respostas possíveis são sempre as mesmas.
| Resposta | Quando | Exemplo |
|---|---|---|
| Mitigar | o controle custa menos que o dano esperado | limite de taxa no login |
| Transferir | outro faz melhor e responde por isso | TLS no Caddy; pagamentos num PSP |
| Evitar | a funcionalidade não paga o risco | não guardar o número do cartão |
| Aceitar | residual pequeno, e registrado | o .deb não é assinado; está escrito |
Políticas#
Uma política que ninguém consegue verificar é um documento. As que funcionam viram verificação automática — e o lugar delas é a esteira de CI.
// Uma politica executavel: a esteira reprova o que a
// politica proibe, e ninguem precisa lembrar de conferir.
// 1. Nenhum segredo entra no repositorio.
// $ dataforge seguranca . --strict
// 2. O analisador nao deixa passar erro.
// $ dataforge check . --strict
// 3. Estilo e higiene.
// $ dataforge lint .
// 4. A suite inteira, com piso de cobertura.
// $ dataforge test tests/ --cobertura --minimo=80
// 5. A superficie nao quebrou sem o bump correspondente.
// $ dataforge abi antes.df depois.df| Política | O comando que a cobra |
|---|---|
| segredo nunca entra no repositório | dataforge seguranca . --strict |
| nenhum erro do analisador | dataforge check . --strict |
| cobertura mínima | dataforge test --cobertura --minimo=80 |
| a versão sobe quando a superfície quebra | dataforge abi |
| as dependências são as do lockfile | dataforge install |