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 WxPay from 'wechatpay-node-v3';
|
||||||
|
import crypto from 'crypto';
|
||||||
import { getEnv } from '@/lib/config';
|
import { getEnv } from '@/lib/config';
|
||||||
import type { WxpayPcOrderParams, WxpayH5OrderParams, WxpayRefundParams } from './types';
|
import type { WxpayPcOrderParams, WxpayH5OrderParams, WxpayRefundParams } from './types';
|
||||||
|
|
||||||
@@ -144,12 +145,14 @@ export async function verifyNotifySign(params: {
|
|||||||
serial: string;
|
serial: string;
|
||||||
signature: string;
|
signature: string;
|
||||||
}): Promise<boolean> {
|
}): Promise<boolean> {
|
||||||
const pay = getPayInstance();
|
const env = getEnv();
|
||||||
return pay.verifySign({
|
if (!env.WXPAY_PUBLIC_KEY) {
|
||||||
timestamp: params.timestamp,
|
throw new Error('WXPAY_PUBLIC_KEY is required for signature verification');
|
||||||
nonce: params.nonce,
|
}
|
||||||
body: params.body,
|
|
||||||
serial: params.serial,
|
// 微信支付公钥模式:直接用公钥验签,不拉取平台证书
|
||||||
signature: params.signature,
|
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) {
|
if (!timestamp || !nonce || !signature || !serial) {
|
||||||
throw new Error('Missing required Wechatpay signature headers');
|
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 });
|
const valid = await verifyNotifySign({ timestamp, nonce, body, serial, signature });
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
throw new Error('Wxpay notification signature verification failed');
|
throw new Error('Wxpay notification signature verification failed');
|
||||||
|
|||||||
Reference in New Issue
Block a user