ai-agents-for-beginners

Assista ao vídeo da lição: Protegendo Agentes de IA com Recibos Criptográficos

(Vídeo da lição e miniatura serão adicionados pela equipe de conteúdo da Microsoft após a mesclagem, seguindo o padrão da lição 14 / 15.)

Protegendo Agentes de IA com Recibos Criptográficos

Introdução

Esta lição irá cobrir:

Objetivos de Aprendizagem

Após concluir esta lição, você saberá como:

O Problema: A Trilha de Auditoria do Seu Agente

Imagine que você implantou um agente de IA para a Contoso Travel. O agente lê solicitações dos clientes, chama uma API de voos para buscar opções e reserva assentos em nome do cliente. No último trimestre, o agente processou 50.000 reservas.

Hoje um auditor chega. Ele faz uma pergunta simples: “Mostre-me o que seu agente fez.”

Você entrega seus arquivos de log. O auditor os analisa e faz a pergunta mais difícil: “Como eu sei que esses logs não foram editados?”

Este é o problema da trilha de auditoria. A maioria das implantações de agentes hoje depende de:

Nenhum deles pode responder à pergunta do auditor sem exigir que o auditor confie em alguém (você, seu provedor de nuvem, seu fornecedor de banco de dados). Para uso interno, essa confiança costuma ser aceitável. Para cargas reguladas (finanças, saúde, qualquer coisa sujeita à Lei de IA da UE), não é.

Recibos criptográficos resolvem isso tornando cada ação do agente verificável de maneira independente. O auditor não precisa confiar em você. Ele precisa apenas da sua chave pública e do próprio recibo.

O que é um Recibo Criptográfico?

Um recibo é um objeto JSON que registra o que um agente fez, assinado com uma assinatura digital.

flowchart LR
    A[Agente invoca uma ferramenta] --> B[Construir carga útil do recibo]
    B --> C[Canonizar JSON RFC 8785]
    C --> D[Hash SHA-256]
    D --> E[Assinatura Ed25519]
    E --> F[Recibo com assinatura]
    F --> G[Auditor verifica offline]
    G --> H{Assinatura válida?}
    H -- yes --> I[Prova à prova de adulteração]
    H -- no --> J[Recibo rejeitado]

Um recibo mínimo é assim:

{
  "type": "agent.tool_call.v1",
  "agent_id": "contoso-travel-bot",
  "tool_name": "lookup_flights",
  "tool_args_hash": "sha256:a3f9c1...",
  "result_hash": "sha256:7b2e1d...",
  "policy_id": "contoso-travel-policy-v3",
  "timestamp": "2026-04-25T14:30:00Z",
  "sequence": 47,
  "previous_receipt_hash": "sha256:9d4e6a...",
  "signature": {
    "alg": "EdDSA",
    "sig": "c5af83...",
    "public_key": "8f3b2c..."
  }
}

Três propriedades fazem o trabalho:

  1. A assinatura. O recibo é assinado pelo gateway do agente usando uma chave privada Ed25519. Qualquer um com a chave pública correspondente pode verificar a assinatura offline. Qualquer alteração em algum campo invalida a assinatura.

  2. Codificação canônica. Antes da assinatura, o recibo é serializado usando o JSON Canonicalization Scheme (JCS, RFC 8785). Isso garante que duas implementações produzindo o mesmo recibo lógico gerem saída byte-idêntica. Sem canonicidade, diferentes serializadores JSON produziriam assinaturas diferentes para o mesmo conteúdo.

  3. Encadeamento por hash. O campo previous_receipt_hash vincula cada recibo ao anterior. Remover ou reordenar um recibo quebra todos os recibos que vieram depois. Adulterações tornam-se visíveis no nível da cadeia mesmo se assinaturas individuais forem burladas.

Juntas, essas propriedades garantem três coisas:

Produzindo um Recibo em Python

Você não precisa de uma biblioteca especial para produzir um recibo. Os primitivos criptográficos são amplamente disponíveis e a lógica são algumas dezenas de linhas de Python.

Os exercícios práticos em code_samples/18-signed-receipts.ipynb mostram o fluxo completo. A versão resumida:

import json
import hashlib
import base64
from nacl import signing
from jcs import canonicalize  # JSON canônico RFC 8785

def b64url_nopad(data: bytes) -> str:
    return base64.urlsafe_b64encode(data).decode("ascii").rstrip("=")

def sha256_canonical(obj) -> str:
    """SHA-256 of a Python object's JCS-canonical JSON form."""
    return f"sha256:{hashlib.sha256(canonicalize(obj)).hexdigest()}"

# Gerar ou carregar uma chave de assinatura (em produção, armazenar em um cofre de chaves)
signing_key = signing.SigningKey.generate()
verify_key = signing_key.verify_key

# Construir a carga útil do recibo (ainda sem assinatura)
tool_args = {"origin": "SYD", "destination": "LAX"}
tool_result = [{"flight": "QF11", "price": 1850, "stops": 0}]

payload = {
    "type": "agent.tool_call.v1",
    "agent_id": "contoso-travel-bot",
    "tool_name": "lookup_flights",
    "tool_args_hash": sha256_canonical(tool_args),
    "result_hash": sha256_canonical(tool_result),
    "policy_id": "contoso-travel-policy-v3",
    "timestamp": "2026-04-25T14:30:00Z",
    "sequence": 0,
    "previous_receipt_hash": None,
}

# Canonicalizar, hash, assinar.
canonical_bytes = canonicalize(payload)
message_hash = hashlib.sha256(canonical_bytes).digest()
signature_bytes = signing_key.sign(message_hash).signature

# Anexar um objeto de assinatura estruturado.
receipt = {
    **payload,
    "signature": {
        "alg": "EdDSA",
        "sig": b64url_nopad(signature_bytes),
        "public_key": b64url_nopad(bytes(verify_key)),
    },
}

Este é todo o pipeline de assinatura. Os exercícios no notebook percorrem cada etapa.

Verificando um Recibo e Detectando Adulteração

A verificação é a operação inversa:

import base64
import hashlib
from nacl import signing
from nacl.exceptions import BadSignatureError
from jcs import canonicalize

def b64url_decode(s: str) -> bytes:
    padding = "=" * ((4 - len(s) % 4) % 4)
    return base64.urlsafe_b64decode(s + padding)

def verify_receipt(receipt: dict) -> bool:
    # A assinatura é um objeto estruturado: {"alg", "sig", "public_key"}.
    sig_obj = receipt.get("signature")
    if not sig_obj or sig_obj.get("alg") != "EdDSA":
        return False

    # Reconstrua a carga útil que foi realmente assinada (tudo exceto a assinatura).
    payload = {k: v for k, v in receipt.items() if k != "signature"}

    canonical_bytes = canonicalize(payload)
    message_hash = hashlib.sha256(canonical_bytes).digest()

    try:
        verify_key = signing.VerifyKey(b64url_decode(sig_obj["public_key"]))
        verify_key.verify(message_hash, b64url_decode(sig_obj["sig"]))
        return True
    except BadSignatureError:
        return False

Esta função recebe um recibo e retorna True se a assinatura for válida, False caso contrário. Sem chamada de rede, sem dependência de serviço, sem necessidade de confiar em terceiros.

Para ver a detecção de adulteração em ação, o notebook mostra:

  1. Produzir um recibo válido e confirmar que verifica.
  2. Modificar um byte do campo tool_args_hash.
  3. Reexecutar a verificação e ver que falha.

Esta é a demonstração prática de que recibos evidenciam adulteração: qualquer modificação, por menor que seja, quebra a assinatura.

Encadeando Recibos para Agentes com Múltiplas Etapas

Um único recibo assinado protege uma ação. Uma cadeia de recibos protege uma sequência.

flowchart LR
    R0[Recibo 0<br/>gênese] --> R1[Recibo 1]
    R1 --> R2[Recibo 2]
    R2 --> R3[Recibo 3]
    R1 -. previous_receipt_hash .-> R0
    R2 -. previous_receipt_hash .-> R1
    R3 -. previous_receipt_hash .-> R2

Cada recibo registra o hash do recibo anterior. Para remover silenciosamente o recibo 2, um atacante precisaria:

Se a chave privada estiver em um cofre de chaves de hardware e você publicar a chave pública com cada recibo, nenhum desses ataques é possível sem detecção.

O notebook mostra:

  1. Construir uma cadeia de três recibos.
  2. Verificar que o previous_receipt_hash de cada recibo corresponde ao hash real do recibo anterior.
  3. Adulterar um recibo no meio e ver a cadeia quebrar exatamente naquele ponto.

Assim você produz uma trilha de auditoria que um auditor externo pode verificar sem precisar confiar em você.

O que os Recibos Provam (e o que Não Provam)

Esta é a seção mais importante da lição. Recibos são poderosos, mas seu poder é limitado.

Recibos provam três coisas:

  1. Atribuição: uma chave específica assinou uma carga útil específica.
  2. Integridade: a carga útil não mudou desde a assinatura.
  3. Ordenação: este recibo veio depois daquele na cadeia de hash.

Recibos NÃO provam:

  1. Correção: que a ação do agente foi a ação correta. Um recibo pode ser assinado para uma resposta errada tão limpidamente quanto para uma correta.
  2. Conformidade com políticas: que a política referida em policy_id foi realmente avaliada, ou que teria permitido esta ação se checada. O recibo registra o que foi afirmado, não o que foi aplicado.
  3. Identidade além da chave: o recibo diz “esta chave assinou este conteúdo.” Não diz “este humano autorizou isto.” Conectar uma chave a uma pessoa ou organização requer infraestrutura de identidade separada (um diretório, registro de chave pública etc.).
  4. Verdade dos inputs: se o agente recebe um prompt manipulado e age com base nele, o recibo registra a ação fielmente. Recibos são posteriores à validação de entrada, não substitutos dela.

Este limite é importante por duas razões:

Um erro comum é supor que “temos recibos” significa “estamos governados.” Não significa. Recibos são a base. Governança é o sistema que você constrói sobre eles.

Referências para Produção

O código Python desta lição é propositalmente minimalista para você poder ler cada linha e entender exatamente o que está acontecendo. Em produção, você tem duas opções:

  1. Construir diretamente sobre os primitivos criptográficos. As 50 linhas que você viu acima são suficientes para muitos casos de uso. PyNaCl (Ed25519) e o pacote jcs (JSON canônico) são bibliotecas bem mantidas e auditadas.

  2. Usar uma biblioteca de recibos de produção. Vários projetos open-source implementam o mesmo padrão com recursos adicionais (rotação de chaves, verificação em lote, distribuição de JWK Set, integração com mecanismos de política):

    • O formato de recibo usado nesta lição segue um Internet-Draft do IETF (draft-farley-acta-signed-receipts) atualmente em processo de padronização.
    • O Microsoft Agent Governance Toolkit compõe recibos com decisões de política baseadas em Cedar; veja o Tutorial 33 naquele repositório para um exemplo completo.
    • Os pacotes protect-mcp (npm) e @veritasacta/verify (npm) oferecem implementação Node para assinatura e verificação offline de recibos, destinados a envolver qualquer servidor MCP com uma trilha de auditoria evidente para adulteração.

A decisão entre criar seu próprio código e usar uma biblioteca é como decidir entre escrever sua própria biblioteca JWT ou usar uma testada: ambos são razoáveis; a biblioteca economiza tempo e reduz superfície de auditoria; o caminho do zero força você a entender cada primitivo. Esta lição ensina o caminho do zero para lhe dar a base para qualquer escolha.

Verificação do Conhecimento

Teste seu entendimento antes de passar para o exercício prático.

1. Um recibo é assinado com a chave privada Ed25519 do agente. O auditor tem apenas a chave pública. O auditor pode verificar o recibo offline?

Resposta Sim. A verificação Ed25519 requer apenas a chave pública e os bytes assinados. Sem chamada de rede, sem dependência de serviço. Esta é a propriedade que torna os recibos úteis em ambientes desconectados, multi-organização ou de baixa confiança.

2. Um atacante modifica o campo policy_id de um recibo para alegar que ele foi regido por uma política mais permissiva. A assinatura foi sobre a carga original. O que acontece na verificação?

Resposta A verificação falha. A assinatura foi calculada sobre os bytes canônicos da carga original; modificar qualquer campo altera os bytes canônicos, o que altera o hash SHA-256, e torna a assinatura inválida. O atacante precisaria da chave privada para produzir uma assinatura nova válida, o que ele não tem.

3. Por que o recibo inclui um tool_args_hash e um result_hash em vez dos argumentos e resultados crus?

Resposta Por duas razões. Primeiro, o recibo pode precisar ser arquivado ou transmitido em ambientes onde vazar o conteúdo cru (dados pessoais, dados comerciais) é problemático. O hash mantém o recibo pequeno e o conteúdo privado; o auditor verifica que o hash corresponde a uma cópia armazenada separadamente do conteúdo real. Segundo, hashes têm tamanho fixo; um recibo com hashes é limitado em tamanho independentemente do tamanho das entradas e saídas.

4. O campo previous_receipt_hash vincula cada recibo ao seu predecessor. Se um atacante excluir silenciosamente um recibo do meio da cadeia, o que se torna inválido?

Resposta Cada recibo que veio depois do excluído. Os campos `previous_receipt_hash` deles não correspondem mais à cadeia real (porque o recibo que referenciavam não existe mais, ou a cadeia agora aponta para um predecessor diferente). Para esconder a exclusão, o atacante precisaria reassinar cada recibo posterior, o que exige a chave privada.

5. Um recibo verifica limpo. Isso prova que a ação do agente foi correta, sólida ou conforme a política?

Resposta Não. Um recibo válido prova três coisas: atribuição (esta chave assinou este conteúdo), integridade (o conteúdo não mudou) e ordenação (este recibo veio depois daquele). Ele NÃO prova que a ação foi correta, que a política nomeada em `policy_id` foi realmente avaliada, ou que o agente seguiu todas as regras. Recibos tornam o comportamento do agente auditável, não necessariamente correto. Este é o limite mais importante da lição.

Exercício Prático

Abra code_samples/18-signed-receipts.ipynb e complete todas as quatro seções:

  1. Seção 1: Assine seu primeiro recibo e verifique-o.
  2. Seção 2: Adultere o recibo e observe a falha na verificação.
  3. Seção 3: Construa uma cadeia de três recibos e verifique a integridade da cadeia.
  4. Seção 4: Aplique o padrão a um agente construído com o Microsoft Agent Framework: envolva uma chamada de ferramenta na assinatura de recibo, depois verifique o recibo independentemente.

Desafio extra 1: estenda o esquema do recibo com um campo adicional de sua escolha (por exemplo, um ID de solicitação para rastreamento), atualize a lógica canônica de assinatura para incluí-lo e confirme que o recibo ainda passa pela verificação sem erros. Depois modifique o campo após a assinatura e confirme que a verificação falha. Isso força você a entender como cada byte da codificação canônica contribui para a assinatura. Desafio avançado 2: Faça o hash SHA-256 de dois dos seus recibos juntos (concatene seus bytes canônicos em uma ordem determinística) e incorpore o resumo resultante como um novo campo em um terceiro recibo antes de assiná-lo. Verifique se os três recibos ainda passam pela ida e volta. Você acabou de construir uma prova de inclusão em um único passo: qualquer pessoa que possuir o terceiro recibo pode provar que os dois primeiros existiam no momento em que ele foi assinado, sem precisar revelar seus conteúdos. Este é o padrão que os recibos de divulgação seletiva usam em escala (compromissos de Merkle, RFC 6962).

Conclusão

Recibos criptográficos fornecem aos agentes de IA uma trilha de auditoria que é:

Eles não substituem a validação de entrada, a aplicação de políticas ou a infraestrutura de identidade. São uma base para essas camadas. Quando você está implantando agentes em cargas de trabalho regulamentadas, fluxos de trabalho multi-organizacionais, ou qualquer ambiente onde um auditor futuro não possa ser assumido como confiável, os recibos são como você torna a trilha de auditoria honesta.

A lição mais importante: os recibos provam quem disse o quê, quando. Eles não provam que o que foi dito é verdadeiro ou correto. Mantenha essa distinção clara. É a diferença entre um sistema de proveniência honesta e um enganoso.

Lista de Verificação para Produção

Quando estiver pronto para avançar desta lição e implantar agentes com assinaturas de recibos em um ambiente real:

Tem Mais Perguntas sobre Segurança em Agentes de IA?

Junte-se ao Microsoft Foundry Discord para encontrar outros aprendizes, participar de horários de atendimento e tirar suas dúvidas sobre Agentes de IA.

Além desta Lição

Esta lição cobre assinatura de recibos simples e sequências encadeadas por hash. Os mesmos primitivos se combinam em vários padrões mais avançados que você pode encontrar conforme sua postura de governança amadurece:

Recursos Adicionais

Lição Anterior

Construindo Agentes de Uso Computacional (CUA)

Próxima Lição

(A ser determinada pelos mantenedores do currículo)


Aviso Legal: Este documento foi traduzido usando o serviço de tradução por IA Co-op Translator. Embora nos esforcemos pela precisão, por favor, esteja ciente de que traduções automatizadas podem conter erros ou imprecisões. O documento original em seu idioma nativo deve ser considerado a fonte autorizada. Para informações críticas, recomenda-se tradução profissional humana. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução.