Assinar e verificar solicitações
A assinatura do pedido comprova a autenticidade do remetente e a integridade do conteúdo. Ao contrário do TLS (que protege o canal), a assinatura de aplicação torna cada mensagem verificável e resistente ao proxy, ao dinheiro e à entrega adiada.
Objetivos:1. Autenticidade (quem enviou) e integridade (não alterada).
2. Inatingibilidade (proteção contra réplicas).
3. Esquenta-se do transporte (funciona sobre HTTP, filas, webhooks).
4. Auditável (reproduzida meses depois).
1) Modelo de ameaça (mínimo)
Trocar corpo/cabeçalho no caminho.
Réplicas (repetição de pedido legítimo).
Downgrade/strip cabeçalhos da assinatura.
Roubo de segredos de integração.
Relógios não incrões (clock skew) e longas filas.
2) Seleção do primitivo
HMAC (simetria): simples e rápido, a chave é armazenada em ambos os lados. Adequado para webhooks B2B e API interna.
RSA/ECDSA (assimetria): chave privada do remetente, pública do destinatário. Adequado para integrações abertas e quando é importante não compartilhar segredo.
mTLS: autenticação mútua a nível de transporte; muitas vezes combinado com NMAS/assinatura corporal.
JWT/JWS: Conveniente para os bearer-tokens e marcações autônomas; para assinar o corpo, é melhor usar a canonização + JWS Detached/HTTP Mensagem Assinaturas.
HTTP Mensagem Assinaturas (assinar as partes selecionadas da consulta): uma abordagem moderna para o REST.
Recomendação: para webhooks - HMAC + timestamp + nonce + canonização corporal; para API público - HTTP Mensagem Assinaturas ou JWS; para riscos elevados - adicione mTLS.
3) Canonização (que assinamos exatamente)
É preciso assinar uma linha definida que seja restaurada igualmente por ambos os lados.
Composição arbitral:
method \n path_with_query_normalized \n content-type \n digest: SHA-256=BASE64(SHA256(body)) \n x-ts: <unix iso> \n x-nonce: <uuid> \n host \n x-tenant: <tenant_id> \n
Linha final:
canonical = join("\n", fields)
signature = HMAC(secret, canonical) # или ECDSA_sign(private_key, canonical)
Regras:
- Normalize o caminho e a ordem dos parâmetros query.
- Espaços/unicode/maiúscula - Fixe (por exemplo, cabeçalho lower-case, trim).
- Grandes corpos - hasteie (Digest), em vez de incluir «como é».
4) Formato de cabeçalho
Exemplo para HMAC:
X-Signature-Alg: hmac-sha256
X-Signature: v1=hex(hmac),ts=1730379005,nonce=550e8400-e29b-41d4-a716-446655440000,kid=prov_42
Digest: SHA-256=BASE64(SHA256(body))
X-Tenant: brand_eu
Exemplo para asimetria (ECDSA P-256):
Signature: keyId="prov_42", alg="ecdsa-p256-sha256",
ts="2025-10-31T12:30:05Z", nonce="550e...", headers="(request-target) host digest x-tenant",
sig="BASE64(raw_signature)"
Onde 'kid '/' keyId' permite selecionar a chave do registro (consulte rotação).
5) Verificação na recepção
Pseudocode:python def verify(request):
1) Basic assert abs (now () - request. ts) <= ALLOWED_SKEW # напр., 300 с assert not replayed(request. nonce, window = TTL) # store nonce/ts in KV
2) Restore canonical canonical = build_canonical (
method=request. method,
path=normalize_path(request. path, request. query),
content_type=request. headers["content-type"],
digest=hash_body(request. body),
ts=request. ts,
nonce=request. nonce,
host=request. headers["host"],
tenant=request. headers. get("x-tenant")
)
3) Get the key key = key_registry. get(request. kid) # secret (HMAC) или public key (ECDSA)
4) Verify if request signature. alg. startswith("hmac"):
ok = hmac_compare(key. secret, canonical, request. signature)
else:
ok = asym_verify(key. public, canonical, request. signature)
5) Solution if not ok: return 401, "SIGNATURE_INVALID"
return 200, "OK"
Constant-time compara HMAC, armazenamento de 'nonce '/' (ts, event _ id)' em KV rápidos (TTL ≥ janela de entrega).
6) Anti-réplicas e janelas
Timestamp + Nince: Rejeite os pedidos mais velhos do que 'pois não' (por exemplo, 5 min) e as repetições de nonce nesta janela.
Para os webhooks, use o 'event _ id' estável e a tabela inbox - é mais confiável do que apenas nance.
A recontratação (retrai) deve usar os mesmos ts/nce/event _ id, em vez de gerar novos.
7) Multi-tenante e regiões
Guarde as chaves per tenant/region: 'kid = <tenant>: <region>: <key _ id>'.
Separe as balas de segredos e limites; cumpra o dado residency.
Em cabeçalhos/canonizações, especifique «X-Tenant» e a região faz parte do contexto a ser verificado.
8) Gerenciamento de chaves e rotação
Registro de chaves (KMS/Vault): 'kid', tipo, algoritmo, status ('ativo', 'deprecating', 'retired'), 'valid _ from/valid _ to'.
Dual-secret: mantenha a chave atual e seguinte ao mesmo tempo (o receptor aceita ambos).
Rotação por horário e evento (comprometimento).
Key pinning (se possível) e restrição de acesso ao material de chave.
Logs de acesso às chaves e acções com elas.
9) Combinação com mTLS e OAuth
mTLS verifica o canal e «quem você é» ao nível do certificado.
A assinatura protege a mensagem (útil através de proxy/keshi/fila).
O OAUTH/JWT complementa a autenticação/autorização, mas por si só não garante a integridade corporal (se não for assinado na canonização).
As melhores práticas são mTLS + assinatura corporal (Digest) + HMAC/ECDSA + curta 'ts' - interdição.
10) Erros e códigos de resposta
'401 SIGNATURA _ INVALID' é uma assinatura/algoritmo errada.
'401 KEY _ REVOKED' - 'kid' inválido/vencido.
'400 TIMESTAMP _ OUT _ OF _ RANGE' - relógio/janela.
409 NONCE _ REPLAYED - Foi detectada uma repetição.
'400 DIGEST _ MISMATCH' - corpo alterado.
'415 UNSUPPORTED _ ALGORITHM' - 'alg' não resolvido.
'429 TOO _ MANY _ ATTEMPTS' - Trottling por chave/tenante.
Dê um pontapé na razão exata no 'erro _ código' da máquina; não devolva os segredos/canonização «como é».
11) Observação e auditoria
Métricas:- `verify_p95_ms`, `verify_error_rate`, `digest_mismatch_rate`, `replay_blocked_rate`, `alg_usage{hmac,ecdsa}`, `clock_skew_ms`.
- Logs (estruturais): «kid», «alg», «tenant», «region», «ts», «nonte», «digest _ hash», «deceção», «reason».
- Tracing: atributos 'signatura. kid`, `signature. alg`, `signature. ts_skew`.
- Auditoria: registro de rotações imutável, uso de chaves e bandeiras de tolerância.
12) Desempenho
Hasteie o corpo com stryming (não mantenha na memória).
Confira as chaves públicas por 'kid' com TTL curto e deficiência por evento.
No edge/gateway, faça verificações preliminares (ts/nce/formato).
O HMAC é mais rápido que o ECDSA; O ECDSA é mais conveniente para integrações externas e chaves «não compartilháveis».
13) Testes
Kits de ficstur: solicitações idênticas → mesma canonização/assinatura; espaços «sujos »/ordem query/títulos são → sustentáveis.
Negative: incorreto 'kid/alg', corpo/host modificado, repetição de nonce, ts antiquado, clock skew.
Property-based: Qualquer solicitação equivalente fornece uma linha canonical.
Interop: verificações de idioma cruzado (Go/Java/Node/Python).
Chaos: atrasos, retais, mudança de chave de voo.
14) Playbooks (runbooks)
1. Saliência de 'SINAL _ INVALID'
Verificar a rotatividade das chaves, o rashincron clock, as alterações de canonização do remetente.
Ativar temporariamente 'dual-accept' para' kid 'antigo, notificar o parceiro.
2. Altura de 'REPLAYED'
Aumentar TTL de armazenamento nonce, reverter retrainers no remetente, verificar clock skew.
Bloquear IP/ASN abusivo em edge.
3. 'DIGEST _ MISMATCH' em massa
Verificar proxy/compressão/reiniciar cabeçalhos; registar a versão de canonização.
Desativar intermediários que violem o corpo/cabeçalho.
4. Comprometer chave
Revoke 'kid' imediatamente, traduzir para 'next _ kid', regenerar todos os segredos/tokens, auditar o acesso.
15) Erros típicos
Assinar «parte do corpo» ou JSON sem fixar a ordem → vulnerável à mudança de campo.
Sem 'Digest', o proxy pode alterar o corpo discretamente.
A janela longa 'ts' sem nonte → uma réplica aberta.
Armazenar segredos em variáveis de ambiente sem KMS/Vault.
Comparar uma assinatura não constant-time.
Ignorar 'hostt'/' path' na canonização → ataque de reenvio.
Misturar 'kid' de diferentes tenentes e regiões.
16) Folha de cheque antes de vender
- Formato de canonização definido (method, path + query, conteúdo-tipo, Digest, ts, nonce, hostt, tenant).
- Implementados HMAC/ECDSA com 'kid', registro de chaves e dual-secret.
- Estão incluídos anti-réplicas (nonce + ts) e armazenamento inbox/event _ id para webhooks.
- Os códigos de erro/política de retrações e trottling per tenant/key foram configurados.
- Observabilidade: métricas de verify, logs, traçados, alertas em picos.
- Rotação de chaves automatizada; auditoria e permissões limitadas.
- Kits de teste de canonização e compatibilidade entre os idiomas.
- Documentação para integradores com exemplo em 3-4 idiomas e ficturas.
- O mTLS está ativado para integrações sensíveis; O JWT é usado apenas como complemento, não substituindo a assinatura do corpo.
Conclusão
A assinatura e a verificação de pedidos não são um título, mas uma disciplina: canonização clara, janelas de tempo curtas, anti-réplicas, rotação de chaves e observabilidade. Construa um padrão único para todas as integrações (API e webhooks), use 'kid '/KMS, adote duas chaves na rotação, e os seus caminhos tornem-se resistentes a sub-menus, previsíveis e fáceis de auditar.