fix: 微信支付回调验签改用公钥直接验证
wechatpay-node-v3 的 verifySign 会尝试拉取平台证书, 但我们使用的是微信支付公钥模式,不需要平台证书。 改用 crypto.createVerify 直接用公钥做 RSA-SHA256 验签。 同时增加 serial 与 WXPAY_PUBLIC_KEY_ID 的匹配校验。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import WxPay from 'wechatpay-node-v3';
|
||||
import crypto from 'crypto';
|
||||
import { getEnv } from '@/lib/config';
|
||||
import type { WxpayPcOrderParams, WxpayH5OrderParams, WxpayRefundParams } from './types';
|
||||
|
||||
@@ -144,12 +145,14 @@ export async function verifyNotifySign(params: {
|
||||
serial: string;
|
||||
signature: string;
|
||||
}): Promise<boolean> {
|
||||
const pay = getPayInstance();
|
||||
return pay.verifySign({
|
||||
timestamp: params.timestamp,
|
||||
nonce: params.nonce,
|
||||
body: params.body,
|
||||
serial: params.serial,
|
||||
signature: params.signature,
|
||||
});
|
||||
const env = getEnv();
|
||||
if (!env.WXPAY_PUBLIC_KEY) {
|
||||
throw new Error('WXPAY_PUBLIC_KEY is required for signature verification');
|
||||
}
|
||||
|
||||
// 微信支付公钥模式:直接用公钥验签,不拉取平台证书
|
||||
const message = `${params.timestamp}\n${params.nonce}\n${params.body}\n`;
|
||||
const verify = crypto.createVerify('RSA-SHA256');
|
||||
verify.update(message);
|
||||
return verify.verify(env.WXPAY_PUBLIC_KEY, params.signature, 'base64');
|
||||
}
|
||||
|
||||
@@ -107,6 +107,12 @@ export class WxpayProvider implements PaymentProvider {
|
||||
if (!timestamp || !nonce || !signature || !serial) {
|
||||
throw new Error('Missing required Wechatpay signature headers');
|
||||
}
|
||||
|
||||
// 验证 serial 匹配我们配置的公钥 ID
|
||||
if (env.WXPAY_PUBLIC_KEY_ID && serial !== env.WXPAY_PUBLIC_KEY_ID) {
|
||||
throw new Error(`Wxpay serial mismatch: expected ${env.WXPAY_PUBLIC_KEY_ID}, got ${serial}`);
|
||||
}
|
||||
|
||||
const valid = await verifyNotifySign({ timestamp, nonce, body, serial, signature });
|
||||
if (!valid) {
|
||||
throw new Error('Wxpay notification signature verification failed');
|
||||
|
||||
Reference in New Issue
Block a user