ai-agents-for-beginners

Watch the lesson video: Securing AI Agents with Cryptographic Receipts

(Vídeo da aula e miniatura a serem adicionados pela equipa de conteúdos da Microsoft após a fusão, seguindo o padrão das aulas 14 / 15.)

Protegendo Agentes IA com Recibos Criptográficos

Introdução

Esta aula irá abordar:

Objetivos de Aprendizagem

Após concluir esta aula, saberá como:

O Problema: Registo de Auditoria do Seu Agente

Imagine que implementou um agente IA para a Contoso Travel. O agente lê pedidos dos clientes, faz chamadas a uma API de voos para procurar opções e reserva lugares em nome do cliente. No último trimestre, o agente processou 50.000 reservas.

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

Entrega os seus ficheiros de log. O auditor analisa-os e faz a pergunta mais difícil: “Como posso saber que estes registos não foram editados?”

Este é o problema do registo de auditoria. A maioria das implementações de agentes hoje em dia baseiam-se em:

Nenhum destes consegue responder à pergunta do auditor sem que este tenha de confiar em alguém (em si, no seu fornecedor de nuvem, no fornecedor da base de dados). Para uso interno, essa confiança é muitas vezes aceitável. Para cargas de trabalho reguladas (finanças, saúde, qualquer coisa sujeita ao Regulamento Europeu de IA), não é.

Recibos criptográficos resolvem isto, tornando cada ação do agente independentemente verificável. O auditor não precisa confiar em si. Só necessita da sua chave pública e do próprio recibo.

O que é um Recibo Criptográfico?

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

flowchart LR
    A[O agente invoca uma ferramenta] --> B[Construir payload do recibo]
    B --> C[Canonizar JSON RFC 8785]
    C --> D[Hash SHA-256]
    D --> E[Assinar 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 pessoa com a chave pública correspondente pode verificar a assinatura offline. Adulterar qualquer campo invalida a assinatura.

  2. Codificação canónica. Antes de assinar, o recibo é serializado usando o Esquema de Canonicalização JSON (JCS, RFC 8785). Isto assegura que duas implementações que produzam o mesmo recibo lógico produzam uma 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 liga cada recibo ao anterior. Remover ou reordenar um recibo quebra todos os recibos seguintes. A adulteração torna-se visível a nível da cadeia, mesmo que as assinaturas individuais sejam contornadas.

Estas propriedades juntas proporcionam três garantias:

Produzir um Recibo em Python

Não precisa de uma biblioteca especial para produzir um recibo. As primitivas criptográficas estão amplamente disponíveis e a lógica é de poucas dezenas de linhas em Python.

Os exercícios práticos em code_samples/18-signed-receipts.ipynb apresentam todo o fluxo. 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 num 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 explicam cada passo detalhadamente.

Verificar um Recibo e Detetar Adulterações

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

    # Reconstrói 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 chamadas à rede, sem dependência de serviços, sem necessidade de confiar em terceiros.

Para ver a deteção de adulterações 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. Voltar a executar a verificação e ver que falha.

Este é um exemplo prático de que os recibos evidenciam adulterações: qualquer modificação, por menor que seja, quebra a assinatura.

Encadear 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 regista o hash do recibo anterior. Para remover silenciosamente o recibo 2, um atacante teria de:

Se a chave privada estiver num cofre hardware e publicar a chave pública com cada recibo, nenhum destes ataques é factível sem deteção.

O notebook explica:

  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. Manipular um recibo no meio e ver a cadeia quebrar nesse ponto.

É assim que se produz um registo de auditoria que um auditor externo pode verificar sem confiar em si.

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

Esta é a secção mais importante desta aula. Recibos são poderosos, mas o seu poder é limitado.

Os 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 foi alterada desde a assinatura.
  3. Ordenação: este recibo veio depois daquele na cadeia de hashes.

Os recibos NÃO provam:

  1. Correcção: que a ação do agente foi a ação correta. Um recibo pode ser assinado por uma resposta errada tão facilmente quanto por uma correta.
  2. Conformidade com a política: que a política referida em policy_id foi efectivamente avaliada ou que teria permitido esta ação se tivesse sido verificada. O recibo regista o que foi reclamado, 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”. Ligar uma chave a uma pessoa ou organização requer uma infraestrutura de identidade separada (directório, registo de chave pública, etc.).
  4. Veracidade das entradas: se o agente recebe um prompt manipulado e age em conformidade, o recibo regista a ação fielmente. Recibos estão depois da validação da entrada, não substituem essa validação.

Este limite é importante por duas razões:

Um erro comum é assumir que “temos recibos” significa “estamos governados”. Não significa. Recibos são uma base. Governança é o sistema que constrói em cima.

Referências para Produção

O código Python nesta aula é intencionalmente minimalista para que possa ler linha a linha e entender exatamente o que acontece. Em produção, tem duas opções:

  1. Construir diretamente sobre as primitivas criptográficas. As 50 linhas que 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 em produção. Vários projetos open-source implementam o mesmo padrão com funcionalidades adicionais (rotação de chaves, verificação em lote, distribuição de JWK Set, integração com motores de política):

    • O formato de recibo usado nesta aula segue um rascunho IETF Internet-Draft (draft-farley-acta-signed-receipts) atualmente no processo de normalização.
    • O Microsoft Agent Governance Toolkit compõe recibos com decisões de política baseadas em Cedar; veja o Tutorial 33 nesse repositório para um exemplo completo.
    • Os pacotes protect-mcp (npm) e @veritasacta/verify (npm) fornecem uma implementação Node para assinatura e verificação offline de recibos, destinada a proteger qualquer servidor MCP com registo de auditoria evidenciando adulteração.

A decisão entre construir a sua solução ou usar uma biblioteca é como decidir entre escrever a sua própria biblioteca JWT ou usar uma testada: ambas razoáveis; a biblioteca poupa tempo e reduz a superfície de auditoria; o caminho do zero força a compreender cada primitiva. Esta aula ensina o caminho do zero para lhe dar a base para qualquer escolha.

Verificação de Conhecimento

Teste a sua compreensão antes de avançar 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. Pode o auditor verificar o recibo offline?

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

2. Um atacante modifica o campo policy_id de um recibo para alegar que estava governado por uma política mais permissiva. A assinatura estava sobre a carga original. O que acontece durante a 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, tornando a assinatura inválida. O atacante precisaria da chave privada para produzir uma assinatura válida nova, e não a tem.

3. Porque é 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 revelar o conteúdo cru (PII, dados comerciais) é problemático. O hashing 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 tem tamanho limitado independentemente do tamanho dos inputs e outputs.

4. O campo previous_receipt_hash liga cada recibo ao seu predecessor. Se um atacante eliminar silenciosamente um recibo do meio da cadeia, o que fica inválido?

Resposta Cada recibo que veio depois do eliminado. Os seus campos `previous_receipt_hash` já não correspondem à cadeia real (porque o recibo a que faziam referência já não existe, ou a cadeia agora aponta para outro predecessor). Para ocultar a eliminação, o atacante teria de re-assinar todos os recibos posteriores, o que requer a chave privada.

5. Um recibo verifica corretamente. Isso prova que a ação do agente estava correcta, sólida ou em conformidade com 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). NÃO prova que a ação foi correta, que a política indicada em `policy_id` foi efectivamente avaliada, ou que o agente seguiu todas as regras. Recibos tornam o comportamento do agente auditável, não necessariamente correcto. Este é o limite mais importante da aula.

Exercício Prático

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

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

Desafio extra 1: alargue o esquema do recibo com um campo adicional à sua escolha (por exemplo, um ID de pedido para rastreio), atualize a lógica canónica de assinatura para o incluir, e confirme que o recibo passa ainda a verificação. Depois modifique o campo após a assinatura e confirme que a verificação falha. Isto obriga a compreender como cada byte da codificação canónica contribui para a assinatura. Desafio extra 2: Faça o hash SHA-256 de dois dos seus recibos juntos (concatene os seus bytes canónicos numa ordem determinística) e incorpore o resumo resultante como um novo campo num terceiro recibo antes de o assinar. Verifique que os três recibos ainda podem ser revertidos para o seu estado original. Acabou de construir uma prova de inclusão em um passo: qualquer pessoa que possua o terceiro recibo pode provar que os dois primeiros existiam na altura em que foi assinado, sem precisar revelar o seu conteúdo. Este é o padrão que os recibos de divulgação seletiva usam em grande escala (compromissos de Merkle, RFC 6962).

Conclusão

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

Eles não substituem a validação de entrada, aplicação de políticas ou infraestrutura de identidade. São uma base para essas camadas. Quando está a colocar agentes em cargas de trabalho reguladas, fluxos de trabalho multi-organização, ou qualquer cenário em que um auditor futuro não possa presumir confiar em si, os recibos são a forma de tornar a trilha de auditoria honesta.

O ponto mais importante: os recibos provam quem disse o quê, quando. Não provam que o que foi dito era verdade ou correto. Mantenha essa distinção bem clara. É a diferença entre um sistema de proveniência honesto e um enganador.

Lista de Verificação para Produção

Quando estiver pronto para passar desta lição para a implementação de agentes assinados com recibos num ambiente real:

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

Junte-se ao Microsoft Foundry Discord para conhecer outros aprendizes, participar em horas de atendimento e obter respostas às suas perguntas sobre Agentes de IA.

Para Além Desta Lição

Esta lição cobre a assinatura com recibo único e sequências encadeadas por hash. Os mesmos primitivos compõem vários padrões mais avançados que poderá encontrar à medida que a sua postura de governação se desenvolve:

Recursos Adicionais

Lição Anterior

Construir Agentes de Uso de Computador (CUA)

Próxima Lição

(A determinar pelos mantenedores do currículo)


Aviso Legal: Este documento foi traduzido utilizando o serviço de tradução automática Co-op Translator. Embora nos esforcemos pela precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa 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 resultantes da utilização desta tradução.