OpenCyber Academy
Engenharia · Capítulo 31 · Português
Código do curso: OCA-134Capítulo 31: OCA-134-C031

Capítulo 31 — Segurança ofensiva autorizada e red team: implementação II

Ensino gratuito e aberto para quem deseja proteger pessoas e tecnologias. Não é preciso criar uma conta para estudar ou consultar as respostas.

Mapa da aula

Aula 31 publicada. Mapa, exemplo, EX091.

flowchart TD
  N0["31.1 Upsert"]
  N1["31.2 Validar na escrita"]
  N2["31.3 Versionamento da API"]
  N3["31.2b Atualizações parciais"]
  N4["31.3b Importação em lote"]
  N5["31.1b Concorrência otimista"]
  N6["Nota de prática"]
  N7["31.4b Migração dos achados armazenados"]
  N0 --> N1 --> N2 --> N3 --> N4 --> N5 --> N6 --> N7
  N7 --> EX["Exemplo resolvido"]
  EX --> Q["Exercício EX091"]

Desenho lógico

flowchart LR
  N0["31.1 Upsert"]
  N1["31.2 Validar na escrita"]
  N2["31.3 Versionamento da API"]
  N3["31.2b Atualizações parciais"]
  N4["31.3b Importação em lote"]
  N5["31.1b Concorrência otimista"]
  N6["Nota de prática"]
  N7["31.4b Migração dos achados armazenados"]
  N0 --> N1 --> N2 --> N3 --> N4 --> N5 --> N6 --> N7 --> Q["EX091"]
[31.1 Upsert]
    |
    v
[31.2 Validar na escrita]
    |
    v
[31.3 Versionamento da API]
    |
    v
[31.2b Atualizações parciais]
    |
    v
[31.3b Importação em lote]
    |
    v
[31.1b Concorrência otimista]
    |
    v
[Nota de prática]
    |
    v
[31.4b Migração dos achados armazenados]
    |
    v
[Exemplo resolvido] --> [Exercício EX091]

Objetivos de aprendizagem

Você vai (1) acrescentar upserts idempotentes de achados; (2) impor validação de esquema na escrita; (3) versionar as respostas da API.

31.1 Upsert

PUT /findings/{id} com o corpo completo; o mesmo id duas vezes gera uma única linha. As impressões digitais de deduplicação (Capítulo 9) propõem ids, as pessoas confirmam.

"""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

PUT com corpo completo e ids estáveis torna as novas tentativas seguras e as duplicatas raras. As impressões digitais propõem; as pessoas confirmam quando colisões podem esconder causas raiz diferentes. A documentação da API de Sam mostra o exemplo do PUT duplo do laboratório de impressões digitais — seis linhas brutas reduzidas a quatro achados únicos — como o padrão normativo para clientes, e um teste de contrato reprova a construção da documentação se esse exemplo se afastar da API em execução.

31.2 Validar na escrita

Rejeite campos desconhecidos e nomes proibidos; force a severidade por um enum. Erros de validação retornam códigos legíveis por máquina para a interface. Enums e nomes proibidos mantêm pontuações vazias e payloads fora, já na borda. Códigos legíveis por máquina deixam a interface explicar sem interpretar inglês. Sam acrescenta um fixture de interface para cada novo código de validação na mesma mudança. Os fixtures de interface mostram a string do código e a explicação para pessoas lado a lado. Cada código novo também aparece no catálogo público de erros usado pelos clientes móveis.

31.3 Versionamento da API

Prefixo /v1/; só mudanças aditivas dentro da v1. Mudanças incompatíveis exigem /v2/ e uma nota de migração para o PulseMap. Regras aditivas na v1 protegem os clientes móveis de quebras surpresa. Rejeitar risk_score impõe a proibição de pontuações vazias vinda dos fundamentos. As notas de migração da v2 são revisadas pelos donos do PulseMap antes do merge. Os testes de compatibilidade de Sam rodam clientes antigos contra servidores novos toda noite. Quando uma quebra dispara, o ticket cita o cliente mais antigo ainda na matriz de suporte — no mês passado foi a versão móvel que ainda enviava risk_score —, para que os donos saibam qual binário precisa mudar antes da janela.

Caso sintético — Riverstone Transit. Um cliente móvel enviou risk_score; o validador o rejeitou — pontuações vazias ficam de fora (Capítulo 15).

31.4 Erros e limites

Chaves de idempotência não podem derivar só do relógio de parede. Chaves de idempotência baseadas no relógio colidem em novas tentativas no mesmo segundo. As chaves precisam incluir o id do achado ou um nonce gerado pelo cliente. Sam rejeita bibliotecas de cliente que fazem hash só de carimbos de tempo, e a mensagem de rejeição cita um formato de chave exigido, para que os autores não inventem outro esquema fraco. Os formatos de chave exigidos são ilustrados com exemplos válidos e inválidos no corpo do erro. Os exemplos inválidos no corpo do erro são gerados a partir do mesmo fixture que os testes usam.

31.2b Atualizações parciais

Um PATCH que permite mudar a severidade sem referências de evidência convida a rebaixamentos silenciosos. Prefira o PUT completo do corpo validado, ou um PATCH restrito que não consiga apagar hashes de evidência nem mudar o status para fechado sem um ponteiro de novo teste. Rebaixamentos silenciosos de severidade sem evidência são como a aceitação de risco se esconde. Superfícies de PATCH restritas tornam impossível fechar sem novo teste. Sam prefere o PUT no SDK oficial e deixa o PATCH para ferramentas administrativas com campos de auditoria extras. Os campos de auditoria do PATCH administrativo incluem a severidade anterior e quem a mudou.

31.3b Importação em lote

A importação em lote de achados vindos de scanners precisa passar pela mesma validação de esquema da criação interativa, incluindo as verificações de campos proibidos e a idempotência por impressão digital. Um caminho separado de "importação confiável" é por onde os payloads entram escondidos no repositório. O job de importação de Sam registra o id do scanner como evidência, nunca como motivo para pular verificações. Pular verificações por causa da marca de um scanner é registrado como wontfix, com um link para esta regra. Importações que falham na validação vão para quarentena com o arquivo do scanner guardado como recebido, para que o fornecedor veja exatamente qual campo foi rejeitado. A mesma impressão digital chegando duas vezes atualiza o achado existente em vez de criar um duplicado.

31.1b Concorrência otimista

Use ETags ou números de versão nos achados, para que dois responsáveis pela remediação não sobrescrevam um ao outro. Uma atualização perdida que apaga um ponteiro de novo teste parece, mais tarde, uma reabertura misteriosa. ETags tornam as atualizações perdidas visíveis como conflitos, em vez de reaberturas misteriosas. Apagar um ponteiro de novo teste numa sobrescrita é um bug de segurança. A interface de Sam força recarregar e mesclar quando chega um 412. As ferramentas de mesclagem nunca apagam automaticamente ponteiros de novo teste ao resolver conflitos. Por isso os robôs de mesclagem automática ficam desativados nos caminhos de achados, e um conflito que mexe num ponteiro de novo teste exige um segundo clique humano, que mostra o valor anterior do ponteiro antes que ele possa ser apagado.

Nota de prática

Exclusões em lote são proibidas sem controle duplo. A exclusão lógica com motivo é o caminho padrão; o expurgo definitivo segue apenas a retenção. Clientes da API que emitem DELETE em laço durante uma nova tentativa com bug têm suas credenciais revogadas automaticamente depois de um limite — outro lugar onde confiabilidade e segurança se encontram.

Documente a semântica do upsert na descrição OpenAPI, para que os clientes móveis não inventem seus próprios ids de nova tentativa.

31.4b Migração dos achados armazenados

Quando o esquema de achados ganha um campo, os registros existentes do FindingsDesk precisam de um valor padrão ou de um preenchimento retroativo. Sam escreve a migração para rodar primeiro numa cópia, compara contagens de registros e checksums antes e depois, e mantém o esquema antigo legível por uma release. Migrações feitas primeiro na cópia, com comparação de checksums, pegam linhas perdidas antes da produção. Manter o esquema antigo legível por uma release amortece clientes lentos. Sam guarda os checksums de antes e depois no ticket da migração, e a lista de verificação da migração recusa o status de concluído até que os dois campos estejam preenchidos e iguais em contagem de registros à pré-cópia.

Exercícios

Síntese

Escritas idempotentes, esquema estrito, versões explícitas.

Continue estudando — capítulo 31 de 50

← Capítulo 30 (rascunho) · Índice de capítulos do curso · Capítulo 32 (rascunho) →

Respostas comentadas

EX091. Uma nova tentativa de rede pode criar dois achados com ids diferentes no servidor; os clientes devem fazer PUT com ids conhecidos.

EX092. {"title":"x","payload":"..."} ou {"password":"..."} ou {"risk_score":42} — qualquer campo proibido/desconhecido pela política.

EX093. Não — renomear quebra os clientes; mantenha reason_code na v1 ou lance a /v2/.