商戶可以按照下述步驟驗(yàn)證應(yīng)答或者回調(diào)的簽名。
如果驗(yàn)證商戶的請(qǐng)求簽名正確,微信支付會(huì)在應(yīng)答的HTTP頭部中包括應(yīng)答簽名。我們建議商戶驗(yàn)證應(yīng)答簽名。
同樣的,微信支付會(huì)在回調(diào)的HTTP頭部中包括回調(diào)報(bào)文的簽名。商戶必須 驗(yàn)證回調(diào)的簽名,以確保回調(diào)是由微信支付發(fā)送。
微信支付API v3使用微信支付 的平臺(tái)私鑰(不是商戶私鑰 )進(jìn)行應(yīng)答簽名。相應(yīng)的,商戶的技術(shù)人員應(yīng)使用微信支付平臺(tái)證書(shū)中的公鑰驗(yàn)簽。目前平臺(tái)證書(shū)只提供API進(jìn)行下載,請(qǐng)參考 獲取平臺(tái)證書(shū)列表。
微信支付的平臺(tái)證書(shū)序列號(hào)位于HTTP頭Wechatpay-Serial
。驗(yàn)證簽名前,請(qǐng)商戶先檢查序列號(hào)是否跟商戶當(dāng)前所持有的 微信支付平臺(tái)證書(shū)的序列號(hào)一致。如果不一致,請(qǐng)重新獲取證書(shū)。否則,簽名的私鑰和證書(shū)不匹配,將無(wú)法成功驗(yàn)證簽名。
首先,商戶先從應(yīng)答中獲取以下信息。
Wechatpay-Timestamp
中的應(yīng)答時(shí)間戳。Wechatpay-Nonce
中的應(yīng)答隨機(jī)串。然后,請(qǐng)按照以下規(guī)則構(gòu)造應(yīng)答的驗(yàn)簽名串。簽名串共有三行,行尾以\n
結(jié)束,包括最后一行。\n
為換行符(ASCII編碼值為0x0A)。若應(yīng)答報(bào)文主體為空(如HTTP狀態(tài)碼為204 No Content
),最后一行僅為一個(gè)\n
換行符。
應(yīng)答時(shí)間戳\n
應(yīng)答隨機(jī)串\n
應(yīng)答報(bào)文主體\n
如某個(gè)應(yīng)答的HTTP報(bào)文為(省略了ciphertext的具體內(nèi)容):
HTTP/1.1 200 OK
Server: nginx
Date: Tue, 02 Apr 2019 12:59:40 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 2204
Connection: keep-alive
Keep-Alive: timeout=8
Content-Language: zh-CN
Request-ID: e2762b10-b6b9-5108-a42c-16fe2422fc8a
Wechatpay-Nonce: c5ac7061fccab6bf3e254dcf98995b8c
Wechatpay-Signature: CtcbzwtQjN8rnOXItEBJ5aQFSnIXESeV28Pr2YEmf9wsDQ8Nx25ytW6FXBCAFdrr0mgqngX3AD9gNzjnNHzSGTPBSsaEkIfhPF4b8YRRTpny88tNLyprXA0GU5ID3DkZHpjFkX1hAp/D0fva2GKjGRLtvYbtUk/OLYqFuzbjt3yOBzJSKQqJsvbXILffgAmX4pKql+Ln+6UPvSCeKwznvtPaEx+9nMBmKu7Wpbqm/+2ksc0XwjD+xlvlECkCxfD/OJ4gN3IurE0fpjxIkvHDiinQmk51BI7zQD8k1znU7r/spPqB+vZjc5ep6DC5wZUpFu5vJ8MoNKjCu8wnzyCFdA==
Wechatpay-Timestamp: 1554209980
Wechatpay-Serial: 5157F09EFDC096DE15EBE81A47057A7232F1B8E1
Cache-Control: no-cache, must-revalidate
{"data":[{"serial_no":"5157F09EFDC096DE15EBE81A47057A7232F1B8E1","effective_time":"2018-03-26T11:39:50+08:00","expire_time":"2023-03-25T11:39:50+08:00","encrypt_certificate":{"algorithm":"AEAD_AES_256_GCM","nonce":"4de73afd28b6","associated_data":"certificate","ciphertext":"..."}}]}
則驗(yàn)簽名串為
1554209980
c5ac7061fccab6bf3e254dcf98995b8c
{"data":[{"serial_no":"5157F09EFDC096DE15EBE81A47057A7232F1B8E1","effective_time":"2018-03-26T11:39:50+08:00","expire_time":"2023-03-25T11:39:50+08:00","encrypt_certificate":{"algorithm":"AEAD_AES_256_GCM","nonce":"4de73afd28b6","associated_data":"certificate","ciphertext":"..."}}]}
微信支付的應(yīng)答簽名通過(guò)HTTP頭Wechatpay-Signature
傳遞。(注意,示例因?yàn)榕虐婵赡艽嬖趽Q行,實(shí)際數(shù)據(jù)應(yīng)在一行)
Wechatpay-Signature: CtcbzwtQjN8rnOXItEBJ5aQFSnIXESeV28Pr2YEmf9wsDQ8Nx25ytW6FXBCAFdrr0mgqngX3AD9gNzjnNHzSGTPBSsaEkIfhPF4b8YRRTpny88tNLyprXA0GU5ID3DkZHpjFkX1hAp/D0fva2GKjGRLtvYbtUk/OLYqFuzbjt3yOBzJSKQqJsvbXILffgAmX4pKql+Ln+6UPvSCeKwznvtPaEx+9nMBmKu7Wpbqm/+2ksc0XwjD+xlvlECkCxfD/OJ4gN3IurE0fpjxIkvHDiinQmk51BI7zQD8k1znU7r/spPqB+vZjc5ep6DC5wZUpFu5vJ8MoNKjCu8wnzyCFdA==
對(duì) Wechatpay-Signature
的字段值使用Base64進(jìn)行解碼,得到應(yīng)答簽名。
很多編程語(yǔ)言的簽名驗(yàn)證函數(shù)支持對(duì)驗(yàn)簽名串和簽名 進(jìn)行簽名驗(yàn)證。強(qiáng)烈建議商戶調(diào)用該類函數(shù),使用微信支付平臺(tái)公鑰對(duì)驗(yàn)簽名串和簽名進(jìn)行SHA256 with RSA簽名驗(yàn)證。
下面展示使用命令行演示如何進(jìn)行驗(yàn)簽。假設(shè)我們已經(jīng)獲取了平臺(tái)證書(shū)并保存為1900009191_wxp_cert.pem
。
首先,從微信支付平臺(tái)證書(shū)導(dǎo)出微信支付平臺(tái)公鑰
$ openssl x509 -in 1900009191_wxp_cert.pem -pubkey -noout > 1900009191_wxp_pub.pem
$ cat 1900009191_wxp_pub.pem
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4zej1cqugGQtVSY2Ah8R
MCKcr2UpZ8Npo+5Ja9xpFPYkWHaF1Gjrn3d5kcwAFuHHcfdc3yxDYx6+9grvJnCA
2zQzWjzVRa3BJ5LTMj6yqvhEmtvjO9D1xbFTA2m3kyjxlaIar/RYHZSslT4VmjIa
tW9KJCDKkwpM6x/RIWL8wwfFwgz2q3Zcrff1y72nB8p8P12ndH7GSLoY6d2Tv0OB
2+We2Kyy2+QzfGXOmLp7UK/pFQjJjzhSf9jxaWJXYKIBxpGlddbRZj9PqvFPTiep
8rvfKGNZF9Q6QaMYTpTp/uKQ3YvpDlyeQlYe4rRFauH3mOE6j56QlYQWivknDX9V
rwIDAQAB
-----END PUBLIC KEY-----
然后,把簽名base64解碼后保存為文件signature.txt
$ openssl base64 -d -A <<< \ 'CtcbzwtQjN8rnOXItEBJ5aQFSnIXESeV28Pr2YEmf9wsDQ8Nx25ytW6FXBCAFdrr0mgqngX3AD9gNzjnNHzSGTPBSsaEkIfhPF4b8YRRTpny88tNLyprXA0GU5ID3DkZHpjFkX1hAp/D0fva2GKjGRLtvYbtUk/OLYqFuzbjt3yOBzJSKQqJsvbXILffgAmX4pKql+Ln+6UPvSCeKwznvtPaEx+9nMBmKu7Wpbqm/+2ksc0XwjD+xlvlECkCxfD/OJ4gN3IurE0fpjxIkvHDiinQmk51BI7zQD8k1znU7r/spPqB+vZjc5ep6DC5wZUpFu5vJ8MoNKjCu8wnzyCFdA==' > signature.txt
最后,驗(yàn)證簽名
$ openssl dgst -sha256 -verify 1900009191_wxp_pub.pem -signature signature.txt << EOF
1554209980
c5ac7061fccab6bf3e254dcf98995b8c
{"data":[{"serial_no":"5157F09EFDC096DE15EBE81A47057A7232F1B8E1","effective_time":"2018-03-26T11:39:50+08:00","expire_time":"2023-03-25T11:39:50+08:00","encrypt_certificate":{"algorithm":"AEAD_AES_256_GCM","nonce":"d215b0511e9c","associated_data":"certificate","ciphertext":"..."}}]}
EOF
Verified OK