Capítulo 9 — Programação II
Mapa da aula
Aula 09 publicada. Mapa, exemplo, EX025.
flowchart TD
N0["9.1 Esquemas sem payloads"]
N1["9.2 Atualizações idempotentes"]
N2["9.3 Testes de propriedade"]
N3["9.2b Migração sem indisponibilidade"]
N4["9.1b Chaves de idempotência a partir de impressões d"]
N5["Síntese"]
N0 --> N1 --> N2 --> N3 --> N4 --> N5
N5 --> EX["Exemplo resolvido"]
EX --> Q["Exercício EX025"]
Desenho lógico
flowchart LR
N0["9.1 Esquemas sem payloads"]
N1["9.2 Atualizações idempotentes"]
N2["9.3 Testes de propriedade"]
N3["9.2b Migração sem indisponibilidade"]
N4["9.1b Chaves de idempotência a partir de impressões d"]
N5["Síntese"]
N0 --> N1 --> N2 --> N3 --> N4 --> N5 --> Q["EX025"]
[9.1 Esquemas sem payloads]
|
v
[9.2 Atualizações idempotentes]
|
v
[9.3 Testes de propriedade]
|
v
[9.2b Migração sem indisponibilidade]
|
v
[9.1b Chaves de idempotência a partir de impressões d]
|
v
[Síntese]
|
v
[Exemplo resolvido] --> [Exercício EX025]
Objetivos de aprendizagem
Você vai (1) desenhar um esquema de achados que proíba receitas de exploração; (2) implementar atualizações idempotentes; (3) usar testes de propriedade para regras de escopo.
9.1 Esquemas sem payloads
O FindingsDesk guarda título, ativo, classe de fraqueza, referência de evidência, impacto, status e carimbos de tempo. Ele não pode guardar um exploit funcional, uma credencial ativa nem um ataque passo a passo. A validação do esquema rejeita campos chamados payload, password ou shell. As evidências ficam num repositório lacrado, referenciado por hash (Capítulo 48). Rejeitar esses nomes de campo na entrada impede que um engenheiro bem-intencionado cole uma senha num ticket durante um encerramento corrido. Evidência por hash significa que o ticket continua compartilhável enquanto o repositório lacrado continua trancado. Sam avalia cada proposta de nova coluna pela mesma regra: se ela puder conter uma receita ou um segredo, não pertence ao FindingsDesk.
9.2 Atualizações idempotentes
Fechar um achado duas vezes precisa deixá-lo fechado; anexar o mesmo hash de evidência duas vezes precisa deixar um único anexo. A idempotência torna seguras as novas tentativas (Capítulo 6). Use um id de achado estável e trate criar-ou-atualizar como uma única operação indexada por esse id.
"""Deduplicate synthetic findings by a stable fingerprint (asset, weakness class, location)."""
import hashlib
raw = [
("web-01", "missing-header", "/login"),
("web-01", "missing-header", "/login"),
("web-01", "missing-header", "/account"),
("web-02", "default-credential", "admin-ui"),
("web-02", "default-credential", "admin-ui"),
("db-01", "weak-tls", "5432"),
]
seen = {}
for asset, cls, loc in raw:
fp = hashlib.sha256(f"{asset}|{cls}|{loc}".encode()).hexdigest()[:10]
seen.setdefault(fp, [asset, cls, loc, 0])[3] += 1
print(f"raw={len(raw)} unique={len(seen)}")
for fp, (a, c, l, n) in sorted(seen.items(), key=lambda x: x[1]):
print(f"{fp} {a:7} {c:19} {l:9} occurrences={n}")
Saída esperada:
raw=6 unique=4
f9bb6de442 db-01 weak-tls 5432 occurrences=1
66fb6f1d56 web-01 missing-header /account occurrences=1
c4bfba3b72 web-01 missing-header /login occurrences=2
296a3331f0 web-02 default-credential admin-ui occurrences=2
Novas tentativas são normais quando os envios falham e, sem idempotência, cada uma reabriria trabalho ou criaria tickets duplicados. Um id estável transforma criação e atualização no mesmo caminho, de modo que a segunda chamada encontra a linha existente. A impressão digital do laboratório reduz seis linhas brutas a quatro achados únicos, que é o que os responsáveis pela remediação querem ver.
9.3 Testes de propriedade
Além dos testes por exemplo, declare uma propriedade: "para todo host na lista de exclusão e toda porta, allowed é False". Gere dezenas de hosts sintéticos e afirme a propriedade. Testes de propriedade pegam o bug em que uma entrada da lista de exclusão é ignorada para portas fora de uma lista fixa no código.
Caso sintético — Riverstone Transit. A deduplicação de seis linhas brutas deixou quatro achados únicos; as duas duplicatas eram o mesmo cabeçalho ausente em /login, relatado por dois scanners. Sam fez da impressão digital (ativo, fraqueza, local) a chave de idempotência.
9.4 Erros e limites
Esquemas derivam; versione-os. Testes de propriedade são tão bons quanto o gerador; inclua à mão os casos de borda conhecidos. Um esquema sem campo de versão obriga os clientes a adivinhar quais campos existem. Geradores que nunca emitem o último endereço de uma faixa nunca vão pegar um bug ali. Sam mantém uma pequena tabela, escrita à mão, de casos traiçoeiros ao lado da suíte de propriedades e roda as duas a cada mudança. Um bug no gerador é tratado como um bug de produto: corrija-o antes do próximo engajamento.
9.2b Migração sem indisponibilidade
Quando o esquema de achados ganha um campo obrigatório, implante uma mudança em duas fases: primeiro aceite e persista o campo como opcional enquanto preenche os registros antigos; depois mude o validador para obrigatório. Engajamentos no meio da janela não podem quebrar porque um cliente móvel está uma versão atrás. Publique a versão do esquema nas respostas da API para que os clientes possam se recusar a escrever quando forem incompatíveis. Mudanças em duas fases mantêm a escrita segura para clientes no meio de um engajamento. O preenchimento retroativo completa as linhas antigas antes de o campo se tornar obrigatório, para que os validadores não rejeitem tickets históricos. Publicar a versão do esquema permite que um cliente móvel recuse uma escrita incompatível em vez de corromper um achado. Sam ensaia a virada numa cópia de staging, com um fixture de engajamento ativo, antes de tocar a produção.
9.1b Chaves de idempotência a partir de impressões digitais
Quando dois scanners relatam a mesma fraqueza, calcule primeiro a impressão digital e use-a para gerar ou localizar o id do achado antes da inserção. Pessoas ainda confirmam as fusões quando as impressões digitais colidem entre causas-raiz diferentes (o mesmo cabeçalho ausente em duas aplicações sem relação). Registre os ids dos scanners como referências de evidência, não como achados separados, para que a remediação acompanhe um único ticket. Os scanners discordam na redação, mas costumam concordar em ativo, classe e local, o que basta para uma impressão digital. Colisões entre aplicações sem relação são raras e exigem uma fusão humana, que sai mais barata que dezenas de tickets duplicados. Guardar os ids dos scanners como evidência preserva a proveniência sem multiplicar o backlog. Sam mostra a impressão digital no ticket para que os responsáveis vejam por que dois alertas viraram um.
Exercícios
- EX025 — Rejeição pelo esquema. Escreva uma regra de validação que rejeite um achado contendo um campo cujo nome case com
(?i)payload|password|passwd|shell. Rubrica: 3 = regra mais um exemplo que falha; 2 = só a regra; 1 = ideia; 0 = nada. - EX026 — Impressão digital. Pelo laboratório, por que duas linhas de /login se fundem e duas de /account não? Rubrica: 3 = mesma impressão digital vs. local diferente; 2 = "mesmo achado"; 1 = vago; 0 = errado.
- EX027 — Propriedade. Declare uma propriedade de
allowedque precisa valer depois de qualquer acréscimo à lista de exclusão. Rubrica: 3 = encolhimento monotônico / todo host excluído sempre negado; 2 = informal; 1 = propriedade errada; 0 = nada.
Síntese
Esquemas, idempotência e propriedades tornam o software de avaliação entediante no bom sentido: previsível sob novas tentativas e revisões.
Continue estudando — capítulo 09 de 50
← Capítulo 08 (rascunho) · Índice de capítulos do curso · Capítulo 10 (rascunho) →