How to Verify WeChat Pay V3 Response Signatures in Java
This guide explains why and how to verify WeChat Pay V3 response signatures using Java, covering certificate serial checks, constructing the verification string from response headers, and performing SHA256‑with‑RSA validation to ensure responses truly originate from the WeChat Pay server.
1. Introduction
WeChat Pay V3 series previously covered request signing and how to obtain and refresh the platform public key; this article continues by explaining how to verify the signature of WeChat Pay response results.
2. Why Verify Response Signature
WeChat Pay includes a signature in the HTTP response headers. Merchants must verify it to ensure the response truly originates from WeChat Pay servers and to prevent man‑in‑the‑middle attacks. Verification requires the platform public key and additional header parameters.
Example of a WeChat Pay server response:
HTTP/1.1 200 OK
Server: nginx
Date: Tue, 02 Apr 2019 12:59:40 GMT
Content-Type: application/json; charset=utf-8
...
Wechatpay-Nonce: c5ac7061fccab6bf3e254dcf98995b8c
Wechatpay-Signature: CtcbzwtQjN8rnOXItEBJ5aQFSnIXESeV28Pr2YEmf9wsDQ8Nx25ytW6FXBCAFdrr0mgqngX3AD9gNzjnNHzSGTPBSsaEkIfhPF4b8YRRTpny88tNLyprXA0GU5ID3DkZHpjFkX1hAp/D0fva2GKjGRLtvYbtUk/OLYqFuzbjt3yOBzJSKQqJsvbXILffgAmX4pKql+Ln+6UPvSCeKwznvtPaEx+9nMBmKu7Wpbqm/+2ksc0XwjD+xlvlECkCxfD/OJ4gN3IurE0fpjxIkvHDiinQmk51BI7zQD8k1znU7r/spPqB+vZjc5ep6DC5wZUpFu5vJ8MoNKjCu8wnzyCFdA==
Wechatpay-Timestamp: 1554209980
Wechatpay-Serial: 5157F09EFDC096DE15EBE81A47057A7232F1B8E1
...
{"prepay_id":"wx2922034726858082fbd40b511c67630000"}Check Platform Certificate Serial Number
The response includes a platform certificate serial number in the Wechatpay-Serial header. This indicates which certificate should be used for verification; if the serial is missing, the certificate must be refreshed. The previous article stored the serial‑certificate pairs in a HashMap, so we only need to check its presence.
Construct the Signature String
Three parameters from the response are needed to build the string that will be verified.
/**
* Build the verification string.
*
* @param wechatpayTimestamp timestamp from Wechatpay‑Timestamp header
* @param wechatpayNonce nonce from Wechatpay‑Nonce header
* @param body response body
* @return the concatenated string
*/
public String responseSign(String wechatpayTimestamp, String wechatpayNonce, String body) {
return Stream.of(wechatpayTimestamp, wechatpayNonce, body)
.collect(Collectors.joining("
", "", "
"));
}Verify the Signature
The signature to verify is obtained from the Wechatpay-Signature header. Using the platform public key, we verify the constructed string with SHA256‑with‑RSA.
// Build the verification string
final String signatureStr = responseSign(wechatpayTimestamp, wechatpayNonce, body);
// Load SHA256withRSA signer
Signature signer = Signature.getInstance("SHA256withRSA");
// Initialize with the platform certificate
signer.initVerify(certificate);
// Update signer with the verification string
signer.update(signatureStr.getBytes(StandardCharsets.UTF_8));
// Verify the Base64‑decoded signature from the header
boolean result = signer.verify(Base64Utils.decodeFromString(wechatpaySignature));Complete Verification Method
/**
* Verify WeChat Pay response signature using the platform certificate.
*
* @param wechatpaySerial current certificate serial number
* @param wechatpaySignature signature from Wechatpay‑Signature header
* @param wechatpayTimestamp timestamp from Wechatpay‑Timestamp header
* @param wechatpayNonce nonce from Wechatpay‑Nonce header
* @param body response body
* @return true if verification succeeds
*/
@SneakyThrows
public boolean responseSignVerify(String wechatpaySerial, String wechatpaySignature,
String wechatpayTimestamp, String wechatpayNonce, String body) {
if (CERTIFICATE_MAP.isEmpty() || !CERTIFICATE_MAP.containsKey(wechatpaySerial)) {
refreshCertificate();
}
Certificate certificate = CERTIFICATE_MAP.get(wechatpaySerial);
final String signatureStr = createSign(wechatpayTimestamp, wechatpayNonce, body);
Signature signer = Signature.getInstance("SHA256withRSA");
signer.initVerify(certificate);
signer.update(signatureStr.getBytes(StandardCharsets.UTF_8));
return signer.verify(Base64Utils.decodeFromString(wechatpaySignature));
}The CERTIFICATE_MAP container for platform certificates is described in the previous article.
3. Summary
Successful verification confirms that the response originates from WeChat Pay, allowing further business logic. Both V2 and V3 APIs require using API certificates for request signing and response verification, which heavily relies on proper use of cryptographic hash algorithms. Mastering this skill gives an edge in interviews and real‑world development.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
