You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP实现Volume支付API签名验证报错求助

Volume Webhook支付签名验证错误排查请求

问题描述

在实现Volume的Webhook支付功能时,生产与本地环境均触发签名验证错误:

  • 生产环境报错:
    error:0480006C:PEM routines::no start line
    error:02000068:rsa routines::bad signature
    error:1C880004:Provider routines::RSA lib
    
  • 本地环境报错:
    error:0909006C:PEM routines:get_name:no start line 
    error:02000068:rsa routines::bad signature
    

测试代码

<?php
    // 加载公钥
    // 来源:https://api.sandbox.volumepay.io/.well-known/signature/pem
    $pemContent = file_get_contents("https://api.sandbox.volumepay.io/.well-known/signature/pem");
    if ($pemContent === false) {
        die("读取公钥失败。\n");
    }

    $publicKey = "-----BEGIN PUBLIC KEY-----\n" . trim($pemContent) . "\n-----END PUBLIC KEY-----";

    // 加载payload
    $payload = '{"paymentId":"a08ff808-53bf-4716-8e0d-c1185c8b0b6b","merchantPaymentId":"payment_6705370a441ed9.34887321","paymentStatus":"FAILED","errorDescription":"Failed to create payment authorization - payment provider returned an error","paymentRequest":{"amount":9.99,"currency":"GBP","reference":"Payment Reference"},"paymentRefundData":null,"paymentMetadata":null,"applicationId":"96c1e0da-93ae-407e-aae5-aa02fa314ff9"}';
    if ($payload === false) {
        die("读取payload失败。\n");
    }

    // 加载并解码Base64签名
    $signatureBase64 = "dllgtxuoO3SKehfxs02i9PF9i32m//xeEUp2CLFWs9RCjbKSTFCbIdFwjlQKDGUrQcZQVfFQ4XFb6/COMB9pUjWcXX874uWJVZvkzzGDaaqwxb9obkte49o73NlfCrfpk/kKE1MJ3rXxeHJTkh2A2AcE4tDBP8V9M+gWmytLbtpLG6MAF/lvze0wqgy8Kg5eQ3nwcAqqMiz1ruK6XFnzMzURHNPo6kyqaSH/3/dL+j89WiISPOYZ9uUuJmmQGHRbFW6Jor2BjDAav9I6fCIcOgsgwQkXYs+hA42JZUV5adrau4gtHEvxfmt8xualaB15+OenKcM+3CgXRkPSTKNmYQ==";
    $signatureBase64 = str_replace('\/', '/', $signatureBase64);
    //$signatureBase64 = str_replace('//', '/', $signatureBase64);
    if ($signatureBase64 === false) {
        die("读取签名失败。\n");
    } else {
        echo "签名Base64: " . $signatureBase64;
    }

    $signature = base64_decode($signatureBase64);

    // 检查签名解码是否成功
    if ($signature === false) {
        die("解码签名失败。\n");
    }else{
         echo "\n签名解码后Base64: " . $signatureBase64;
    }

    // 计算payload的SHA-256哈希
    $hashedPayload = hash('sha256', $payload, true);

    // 初始化公钥资源
    $publicKeyResource = openssl_pkey_get_public($publicKey);
    if ($publicKeyResource === false) {
        die("加载公钥资源失败。\n");
    }

    // 执行签名验证
    $result = openssl_verify($hashedPayload, $signature, $publicKeyResource, OPENSSL_ALGO_SHA256);
    echo "\n验证结果: " . $result . "\n";

    // 释放公钥资源
    openssl_free_key($publicKeyResource);

    echo "Payload:\n{$payload}\n\n";
    echo "Payload的SHA-256哈希: " . bin2hex($hashedPayload) . "\n\n";
    echo "解码后的签名(Hex): " . bin2hex($signature) . "\n\n";

    if ($result === 1) {
        echo "签名验证成功。\n"; 
    } elseif ($result === 0) {
        echo "签名验证失败: 签名不匹配。\n";
        while ($error = openssl_error_string()) {
            echo("OpenSSL验证错误: {$error} \n");
        }
        return false;
    } else {
        while ($error = openssl_error_string()) {
            echo("OpenSSL验证过程错误: {$error} \n");
        }
        return false;
    }
?>

运行输出

$ php index.php 
签名Base64: dllgtxuoO3SKehfxs02i9PF9i32m//xeEUp2CLFWs9RCjbKSTFCbIdFwjlQKDGUrQcZQVfFQ4XFb6/COMB9pUjWcXX874uWJVZvkzzGDaaqwxb9obkte49o73NlfCrfpk/kKE1MJ3rXxeHJTkh2A2AcE4tDBP8V9M+gWmytLbtpLG6MAF/lvze0wqgy8Kg5eQ3nwcAqqMiz1ruK6XFnzMzURHNPo6kyqaSH/3/dL+j89WiISPOYZ9uUuJmmQGHRbFW6Jor2BjDAav9I6fCIcOgsgwQkXYs+hA42JZUV5adrau4gtHEvxfmt8xualaB15+OenKcM+3CgXRkPSTKNmYQ==
签名解码后Base64: dllgtxuoO3SKehfxs02i9PF9i32m//xeEUp2CLFWs9RCjbKSTFCbIdFwjlQKDGUrQcZQVfFQ4XFb6/COMB9pUjWcXX874uWJVZvkzzGDaaqwxb9obkte49o73NlfCrfpk/kKE1MJ3rXxeHJTkh2A2AcE4tDBP8V9M+gWmytLbtpLG6MAF/lvze0wqgy8Kg5eQ3nwcAqqMiz1ruK6XFnzMzURHNPo6kyqaSH/3/dL+j89WiISPOYZ9uUuJmmQGHRbFW6Jor2BjDAav9I6fCIcOgsgwQkXYs+hA42JZUV5adrau4gtHEvxfmt8xualaB15+OenKcM+3CgXRkPSTKNmYQ==
验证结果: 0
Payload:
{"paymentId":"a08ff808-53bf-4716-8e0d-c1185c8b0b6b","merchantPaymentId":"payment_6705370a441ed9.34887321","paymentStatus":"FAILED","errorDescription":"Failed to create payment authorization - payment provider returned an error","paymentRequest":{"amount":9.99,"currency":"GBP","reference":"Payment Reference"},"paymentRefundData":null,"paymentMetadata":null,"applicationId":"96c1e0da-93ae-407e-aae5-aa02fa314ff9"}

Payload的SHA-256哈希: 4e41719f186a3d94cc54a5e569107ea5901a516980527904affba2b34e1c69c8

解码后的签名(Hex): 765960b71ba83b748a7a17f1b34da2f4f17d8b7da6fffc5e114a7608b156b3d4428db2924c509b21d1708e540a0c652b41c65055f150e1715bebf08e301f6952359c5d7f3be2e589559be4cf318369aab0c5bf686e4b5ee3da3bdcd95f0ab7e993f90a135309deb5f1787253921d80d80704e2d0c13fc57d33e8169b2b4b6eda4b1ba30017f96fcded30aa0cbc2a0e5e4379f0700aaa322cf5aee2ba5c59f33335111cd3e8ea4caa6921ffdff74bfa3f3d5a22123ce619f6e52e26699018745b156e89a2bd818c301abfd23a7c221c3a0b20c1091762cfa1038d8965457969dadabb882d1c4bf17e6b7cc6e6a5681d79f8e7a729c33edc28174643d24ca36661

签名验证失败: 签名不匹配。
OpenSSL验证错误: error:0480006C:PEM routines::no start line 
OpenSSL验证错误: error:02000068:rsa routines::bad signature 
OpenSSL验证错误: error:1C880004:Provider routines::RSA lib 

问题排查与解决方案

1. 修复PEM格式错误(no start line)

你拼接公钥的逻辑存在问题:

  • trim($pemContent)会移除所有换行符,导致公钥内容不符合PEM规范(要求每64字符分一行)。
  • 正确做法是保留原公钥的换行结构,仅在缺失头尾标识时补充。

修改公钥加载代码:

$pemContent = file_get_contents("https://api.sandbox.volumepay.io/.well-known/signature/pem");
if ($pemContent === false) {
    die("读取公钥失败。\n");
}

// 检查是否已包含PEM头尾标识,缺失则补充
if (!str_contains($pemContent, "-----BEGIN PUBLIC KEY-----")) {
    $publicKey = "-----BEGIN PUBLIC KEY-----\n" . $pemContent . "\n-----END PUBLIC KEY-----";
} else {
    $publicKey = $pemContent;
}

2. 修正签名验证逻辑

openssl_verify不需要手动计算payload的哈希,函数会自动按指定算法处理:

  • 当前代码传入的是预哈希后的$hashedPayload,但函数需要原始payload,它会重新执行哈希并验证签名。

修改验证逻辑:

// 移除手动计算哈希的代码
// $hashedPayload = hash('sha256', $payload, true);

// 直接传入原始payload进行验证
$result = openssl_verify($payload, $signature, $publicKeyResource, OPENSSL_ALGO_SHA256);

3. 移除多余的Base64处理

str_replace('\/', '/', $signatureBase64)属于冗余操作,签名的Base64不会包含转义斜杠,只有从JSON字符串中读取时才需要处理,直接解码即可。

4. 额外检查项

  • 生产环境需使用对应环境的公钥,不要混用沙箱环境的公钥。
  • 接收Webhook时,必须保证原始payload的字符、格式、编码完全一致,不能做任何修改(包括空格、换行、引号)。

修改后的完整测试代码

<?php
// 加载公钥
$pemContent = file_get_contents("https://api.sandbox.volumepay.io/.well-known/signature/pem");
if ($pemContent === false) {
    die("读取公钥失败。\n");
}

// 确保公钥格式合规
if (!str_contains($pemContent, "-----BEGIN PUBLIC KEY-----")) {
    $publicKey = "-----BEGIN PUBLIC KEY-----\n" . $pemContent . "\n-----END PUBLIC KEY-----";
} else {
    $publicKey = $pemContent;
}

// 加载payload
$payload = '{"paymentId":"a08ff808-53bf-4716-8e0d-c1185c8b0b6b","merchantPaymentId":"payment_6705370a441ed9.34887321","paymentStatus":"FAILED","errorDescription":"Failed to create payment authorization - payment provider returned an error","paymentRequest":{"amount":9.99,"currency":"GBP","reference":"Payment Reference"},"paymentRefundData":null,"paymentMetadata":null,"applicationId":"96c1e0da-93ae-407e-aae5-aa02fa314ff9"}';
if ($payload === false) {
    die("读取payload失败。\n");
}

// 解码签名
$signatureBase64 = "dllgtxuoO3SKehfxs02i9PF9i32m//xeEUp2CLFWs9RCjbKSTFCbIdFwjlQKDGUrQcZQVfFQ4XFb6/COMB9pUjWcXX874uWJVZvkzzGDaaqwxb9obkte49o73NlfCrfpk/kKE1MJ3rXxeHJTkh2A2AcE4tDBP8V9M+gWmytLbtpLG6MAF/lvze0wqgy8Kg5eQ3nwcAqqMiz1ruK6XFnzMzURHNPo6kyqaSH/3/dL+j89WiISPOYZ9uUuJmmQGHRbFW6Jor2BjDAav9I6fCIcOgsgwQkXYs+hA42JZUV5adrau4gtHEvxfmt8xualaB15+OenKcM+3CgXRkPSTKNmYQ==";
$signature = base64_decode($signatureBase64);

if ($signature === false) {
    die("解码签名失败。\n");
}

// 初始化公钥资源
$publicKeyResource = openssl_pkey_get_public($publicKey);
if ($publicKeyResource === false) {
    die("加载公钥资源失败。\n");
}

// 执行签名验证
$result = openssl_verify($payload, $signature, $publicKeyResource, OPENSSL_ALGO_SHA256);
echo "\n验证结果: " . $result . "\n";

// 释放资源
openssl_free_key($publicKeyResource);

echo "Payload:\n{$payload}\n\n";

if ($result === 1) {
    echo "签名验证成功。\n"; 
} elseif ($result === 0) {
    echo "签名验证失败: 签名不匹配。\n";
    while ($error = openssl_error_string()) {
        echo("OpenSSL验证错误: {$error} \n");
    }
    exit(1);
} else {
    while ($error = openssl_error_string()) {
        echo("OpenSSL验证过程错误: {$error} \n");
    }
    exit(1);
}
?>

内容的提问来源于stack exchange,提问作者Cleber Castiglioni

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 10:02:03