跳转到内容
PGSwift Docs
文档/签名验证

签名验证

当网关向您的端点发送 Webhook 时,会使用其私钥对请求进行签名。您必须使用 网关的公钥(在入驻时提供)验证 X-SIGNATURE 请求头,以确认请求的真实性。

工作原理

Webhook 签名验证是签名生成的逆过程:

步骤 生成签名(您的 API 调用) 验证签名(传入的 Webhook)
使用的密钥 您的私钥 网关的公钥
操作 签署请求 验证签名
目的 证明请求来自您 确认请求来自网关

验证算法

  1. 从传入请求中提取三个请求头:X-SIGNATURE、X-TIMESTAMP、X-PARTNER-ID
  2. 读取原始请求体
  3. 计算:SHA256(body) → 小写十六进制字符串
  4. 构建:stringToVerify = POST:{webhook_path}:{payload_hash}:{X-TIMESTAMP}
  5. 使用网关的公钥通过 RSA-SHA256 验证签名

代码示例

<?php

function verifyWebhookSignature(
    string $webhookPath,
    string $rawBody,
    string $timestamp,
    string $receivedSignature,
    string $publicKeyPath
): bool {
    // 第一步:对原始请求体进行哈希
    $payloadHash = strtolower(bin2hex(hash('sha256', $rawBody, true)));

    // 第二步:构建待验证字符串
    $stringToVerify = "POST:{$webhookPath}:{$payloadHash}:{$timestamp}";

    // 第三步:加载网关的公钥
    $publicKey = openssl_get_publickey('file://' . $publicKeyPath);
    if (!$publicKey) {
        throw new RuntimeException('无法加载公钥');
    }

    // 第四步:验证签名
    $result = openssl_verify(
        $stringToVerify,
        base64_decode($receivedSignature),
        $publicKey,
        OPENSSL_ALGO_SHA256
    );

    return $result === 1;
}

// 在您的 Webhook 处理程序中使用:
$rawBody = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_SIGNATURE'] ?? '';
$timestamp = $_SERVER['HTTP_X_TIMESTAMP'] ?? '';
$partnerId = $_SERVER['HTTP_X_PARTNER_ID'] ?? '';

// 验证 Partner ID 是否匹配您的客户端密钥
if ($partnerId !== 'your-client-key') {
    http_response_code(401);
    exit('无效的 Partner ID');
}

// 验证签名
$isValid = verifyWebhookSignature(
    '/api/webhooks/payment',   // 您的 Webhook 端点路径
    $rawBody,
    $timestamp,
    $signature,
    '/path/to/gateway-public-key.pem'
);

if (!$isValid) {
    http_response_code(401);
    exit('无效的签名');
}

// 签名验证通过 — 处理 Webhook
$payload = json_decode($rawBody, true);
$event = $payload['event'];
$data = $payload['data'];

// 处理事件...
http_response_code(200);
echo 'OK';

安全检查清单

  • 验证 X-SIGNATURE — 使用网关的公钥验证每个传入的 Webhook
  • 验证 X-PARTNER-ID — 确认与您的客户端密钥匹配
  • 检查 X-TIMESTAMP 时效性 — 拒绝超过 5 分钟的请求以防止重放攻击
  • 使用 HTTPS 作为 Webhook 端点
  • 读取原始请求体进行签名验证,再解析 JSON — 中间件如果解析/重新序列化请求体可能会修改内容导致验证失败
© 2026 PGSwift. 保留所有权利。