利用签名收据证明 API 数据 —— 超越支付验证

利用签名收据证明 API 数据 —— 超越支付验证

如何利用可验证收据在自主 Agent 与按调用付费的 API 之间建立信任

Agent 对 Agent 支付的新时代

AI Agent 首次拥有了自主付费的能力。x402 协议重用了 HTTP 402 Payment Required 状态码,允许客户端(无论是人类还是人工智能)使用 USDC 稳定币按 API 调用付费,彻底跳过 API 密钥,且无需创建账户。

这确实非常巧妙。但在 Agent 开始根据数据采取行动之前,存在一个无人提及的问题。

站在 2026 年 6 月 30 日这个时间节点,我们正处于一个转折点。大语言模型在编排任务方面变得越来越聪明,自主 Agent 正在生产环境中部署,即时为服务付费的能力正成为基本门槛。然而,当前的支付凭证——区块链上的交易——仅确认了交易的一半:资金转移了。它丝毫无法说明您作为回报接收到的数据是否真实或已被篡改。

Agent 可以完美完成支付,但仍然可能根据伪造的数据采取行动。

支付凭证无法证明数据的真实性

假设您构建了一个每次调用收费 0.05 USDC 的 API。客户的 Agent 请求您的端点,x402 流程完成,USDC 完成转账,Agent 收到返回的数据。您的支付系统可以证明交易在链上发生了。

但是谁来验证响应体(response body)确实来自您呢?区块链无法保证这一点。支付收据是一张意图证书,而非真实性证书。具有网络拦截能力的攻击者——甚至是 Agent 与您的 API 之间带有 Bug 的代理服务器——都可以塞入修改过的数据,而支付凭证此时毫无意义。

这是一个真实的隐患,而且规模越大越严重。如果 Agent 在多个 API 之间链式调用,分别向不同的提供商购买数据,它们就需要密码学保证,确保它们收到的就是它们所付费购买的内容。否则,它们就像在盲飞,将决策押在无法验证的数据上。

解决方案:签名收据

解决办法是将支付凭证与数据本身绑定。当您的 API 向付费客户发出响应时,您使用私钥同时对响应体和支付交易 ID 进行签名。客户会收到:

  1. 数据本身。
  2. 证明支付在链上发生的收据。
  3. 将两者绑定在一起的密码学签名。

现在 Agent 可以独立验证:此数据来自此 API,此支付真实存在,并且二者相互匹配。除了在设置时验证一次您的公钥外,无需信任任何其他东西。

这并非革命性的概念——签名收据和 RSA 一样古老——但它是将 x402 从单纯的支付原语转变为完整验证系统的关键拼图。

使用 Express 构建

以下是实现方式。您需要一个密钥对(Ed25519 即可)、一种检测调用何时已付费的方法,以及用于对响应进行签名的中间件。

首先,设置您的密钥和依赖项:

npm install express tweetnacl base64-js axios

生成您的密钥对并安全地存储它(切勿存入 git):

const nacl = require('tweetnacl');
const base64js = require('base64-js');

const keyPair = nacl.sign.keyPair();
const publicKey = base64js.fromByteArray(keyPair.publicKey);
const secretKey = base64js.fromByteArray(keyPair.secretKey);

console.log('Public Key:', publicKey);
console.log('Secret Key:', secretKey);

接下来,创建在支付检查之后拦截响应的中间件:

const express = require('express');
const app = express();

const verifyPayment = async (req, res, next) => {
  const paymentTxId = req.headers['x-payment-tx-id'];
  
  if (!paymentTxId) {
    return res.status(402).json({
      error: 'Payment Required',
      message: 'Provide a payment transaction ID'
    });
  }
  
  // Verify the tx on chain (sketch version)
  const txValid = await verifyTransactionOnChain(paymentTxId, 'REPLACE_WITH_VAULT_REFERENCE');
  
  if (!txValid) {
    return res.status(402).json({ error: 'Invalid payment' });
  }
  
  req.paymentTxId = paymentTxId;
  next();
};

现在创建一个响应签名中间件:

const nacl = require('tweetnacl');
const base64js = require('base64-js');

const secretKey = base64js.toByteArray(process.env.API_SECRET_KEY);

const signResponse = (req, res, next) => {
  const originalJson = res.json.bind(res);
  
  res.json = function(data) {
    const payload = JSON.stringify({
      data: data,
      txId: req.paymentTxId,
      timestamp: Date.now()
    });
    
    const message = Buffer.from(payload);
    const signature = nacl.sign.detached(message, secretKey);
    const signatureBase64 = base64js.fromByteArray(signature);
    
    res.setHeader('X-Signature', signatureBase64);
    res.setHeader('X-Payload-Hash', payload);
    
    return originalJson({ data, receipt: { txId: req.paymentTxId, signature: signatureBase64 } });
  };
  
  next();
};

app.use(verifyPayment);
app.use(signResponse);

最后,添加一个端点:

app.get('/data/:id', (req, res) => {
  const result = { userId: req.params.id, balance: 42, updated: '2026-06-30' };
  res.json(result);
});

app.listen(3000, () => console.log('Listening on :3000'));

在客户端,在根据数据采取行动之前验证签名:

const nacl = require('tweetnacl');
const base64js = require('base64-js');

const publicKey = base64js.toByteArray('REPLACE_WITH_YOUR_PUBLIC_KEY');

function verifyReceipt(response) {
  const signature = base64js.toByteArray(response.headers['x-signature']);
  const payload = response.headers['x-payload-hash'];
  const message = Buffer.from(payload);
  
  const isValid = nacl.sign.detached.verify(
    message,
    signature,
    publicKey
  );
  
  if (!isValid) throw new Error('Signature verification failed');
  return response.data;
}

const response = await fetch('http://app.example.com/data/user123', {
  headers: { 'X-Payment-Tx-Id': 'USDC_TXN_ABC123' }
});

const verified = verifyReceipt(response);
console.log('Trusted data:', verified);

为什么这在生产环境中至关重要

这种模式带来了多项突破。Agent 现在可以无需信任地从以前从未接触过的 API 购买数据。审计人员可以验证决策链是基于真实且已付费的数据。而 API 提供商则能获得明确的密码学证明,证明他们交付了所承诺的内容。

它还具有出色的扩展性。一个签名覆盖一次响应。如果您需要数百万次调用的证明,可以在提供商侧将它们打包到一个 Merkle 树中,并为每个批次颁发一个统一签名。客户只需验证一次批次根(batch root),即可信任其下的所有内容。

结论

x402 协议解决了自主 Agent API 的支付问题。签名收据解决了数据的真实性问题。二者结合,使 Agent 能够可靠地从不可信来源购买数据,并充满信心地下达决策。

优点

  • Agent 可以验证数据完整性,除了公钥外无需信任 API 提供商。
  • 支付与数据在密码学上紧密绑定——无法单独伪造其中之一。
  • 通过 Merkle 树或批签名,可从单次调用轻松扩展至数百万次调用。
  • 无需新的基础设施——仅需标准密码学和现有的区块链。
  • 兼容现有的 x402 支付流程。

缺点

  • 增加延迟:每个响应都必须进行签名(尽管对大多数使用场景来说是可以接受的)。
  • 需要提供商侧具备安全的密钥管理——密钥泄漏将导致信任失效。
  • 客户端必须实现签名验证(对于初学者来说并非易事)。
  • 无法防止 API 提供商对虚假数据进行签名(信任建立在公钥上,而非提供商的诚实度)。
  • 增加了 API 契约的复杂性——客户端和服务器必须就 Payload 格式达成一致。

注意事项

名称 app.example.com, REPLACE_WITH_VAULT_REFERENCE, REPLACE_WITH_YOUR_PUBLIC_KEY,以及此处显示的所有交易 ID 均为占位符。切勿在代码中硬编码私钥、API 密钥或真实凭据。在部署到生产环境之前,务必在本地测试环境中测试签名验证。将私钥存储在密钥保管库(如 HashiCorp Vault、AWS Secrets Manager 或类似服务)中,切勿存储在环境变量或版本控制中。风险自负,请在接受真实支付之前在测试网环境中彻底验证实现。

常见问题

  • 如果 API 提供商的私钥泄露了会怎样?
  • 我可以将多个 API 调用打包成单个签名收据吗?
  • 如何在 JavaScript 以外的语言中验证签名?
  • 我需要对响应中的每个字段都进行签名,还是只需要对数据进行签名?
  • 签名和验证签名的性能开销是多少?
  • 这适用于按固定订阅收费而非按调用次数收费的 API 吗?
  • 在生产环境中,Agent 如何处理签名验证失败的情况?
  • Ed25519 是我唯一应该使用的签名算法吗?还是可以使用其他算法?

标签

#x402 #web3 #api #usdc #cryptography #agents #authentication #blockchain

Free field guide

Incident Response: First Hour

A calm, evidence-preserving checklist for establishing control, bounding impact, communicating clearly, and containing an incident safely.