# 概述
在微信支付API v3的所有請求應(yīng)答場景,開發(fā)者都需要進(jìn)行簽名驗(yàn)簽。如果你是第一次接入微信支付API v3接口,請仔細(xì)閱讀以下系列文檔,并跟著示例操作一次,這將有效幫忙你理解簽名驗(yàn)簽機(jī)制,解決簽名驗(yàn)簽報錯。
1、所有請求商戶都需要使用【商戶API證書私鑰】對請求進(jìn)行簽名,微信支付會在收到請求后使用【商戶API證書公鑰】進(jìn)行簽名的驗(yàn)證。如果簽名驗(yàn)證不通過,微信支付API v3將會拒絕處理請求,并返回401 Unauthorized。
2、所有應(yīng)答,微信支付都會使用平臺證書私鑰簽名,商戶需要使用平臺證書公鑰驗(yàn)證簽名.(文件下載接口和首次下載平臺證書除外)
本文介紹如何驗(yàn)證簽名,計算簽名部分文檔說明請參考操作指引-如何生成請求簽名 (opens new window)。
1、微信支付在 API 應(yīng)答的 HTTP 頭部 Wechatpay-Signature
中提供了應(yīng)答簽名。商戶應(yīng)驗(yàn)證應(yīng)答簽名,以確保數(shù)據(jù)來自微信支付且未經(jīng)第三方篡改。
2、在通知回調(diào)的 HTTP 頭部中,微信支付會包含回調(diào)報文的簽名。商戶必須驗(yàn)證回調(diào)的簽名,以確保回調(diào)由微信支付發(fā)送。
請參考以下內(nèi)容,自行驗(yàn)證簽名,并遵循指引防止重放攻擊,以及應(yīng)對簽名探測流量。
驗(yàn)證簽名分為獲取平臺證書、構(gòu)造驗(yàn)簽串、獲取應(yīng)答簽名、驗(yàn)證簽名共4步
# 1、獲取平臺證書
# 1.1 首次下載證書
第一次獲取平臺證書需要通過證書工具,請按照以下3個步驟操作
(1)點(diǎn)擊這里 (opens new window)下載jar包
(2)執(zhí)行以下命令
1java -jar CertificateDownloader.jar -k ${apiV3key} -m ${mchId} -f ${mchPrivateKeyFilePath} -s ${mchSerialNo} -o ${outputFilePath}
你會得到平臺證書,文件名類似于wechatpay_123456777B4A9CC78902B44B65E04B9751CE12.pem
。
參數(shù)說明
- apiV3key:是指APIv3密鑰,在賬號中心->API安全->APIv3密鑰中設(shè)置,如何獲取APIv3密鑰具體操作參考這里 (opens new window)
- mchId:是指商戶號
- mchPrivateKeyFilePath:商戶API證書私鑰存放的路徑,你需要獲取商戶API證書私鑰(apiclient_key.pem),并保存到某個路徑。如何獲取商戶API證書私鑰具體操作參考這里 (opens new window)
- mchSerialNo:商戶API證書的序列號,如何查看序列號請參考證書相關(guān)問題 (opens new window)
- outputFilePath:平臺證書保存的路徑,開發(fā)者自定義
(3)驗(yàn)證證書有效性
第一次下載證書后,我們強(qiáng)烈建議參考如何通過證書信任鏈驗(yàn)證平臺證書 (opens new window),驗(yàn)證證書的真實(shí)性。
# 1.2 二次獲取平臺證書
除了首次下載證書需要通過以上方式,后續(xù)下載證書請使用微信支付平臺證書下載接口
# 2. 構(gòu)造驗(yàn)簽名串
# 2.1 構(gòu)造驗(yàn)簽串前的檢查
- 您應(yīng)先檢查 HTTP 頭 Wechatpay-Serial 的內(nèi)容是否跟商戶當(dāng)前所持有的微信支付平臺證書的序列號一致。若不一致,請重新獲取證書。否則,簽名的私鑰和證書不匹配,將驗(yàn)證失敗。
- 重放攻擊 (opens new window)是指攻擊者截取報文及其簽名,并以惡意或欺詐目的重新傳輸數(shù)據(jù)的一種攻擊手段。為了降低此類攻擊的風(fēng)險,微信支付在 HTTP 頭
Wechatpay-Timestamp
中提供了生成簽名的時間戳。若微信支付需要重新發(fā)送某個通知回調(diào),我們也會重新生成相應(yīng)的時間戳和簽名。在驗(yàn)證簽名之前,商戶系統(tǒng)應(yīng)檢查時間戳是否已過期。我們建議商戶系統(tǒng)允許最多5分鐘的時間偏差。如果時間戳與當(dāng)前時間的偏差超過5分鐘,您應(yīng)拒絕處理當(dāng)前的響應(yīng)或回調(diào)通知。
提示
您應(yīng)當(dāng)采用網(wǎng)絡(luò)時間協(xié)議(NTP)等機(jī)制實(shí)現(xiàn)商戶系統(tǒng)的時鐘同步,保證時間準(zhǔn)確。
# 2.2開始構(gòu)造驗(yàn)簽串
以某次native下單接口的應(yīng)答為例
1Server: nginx2Date: Mon, 05 Aug 2024 09:33:41 GMT3Content-Type: application/json; charset=utf-84Content-Length: 525Connection: keep-alive6Keep-Alive: timeout=87Cache-Control: no-cache, must-revalidate8X-Content-Type-Options: nosniff9Request-ID: 08F5B8C2B506102C18FDDFEEA30620BE821E28EDC405-010Content-Language: zh-CN11Wechatpay-Nonce: d824f2e086d3c1df967785d13fcd22ef12Wechatpay-Signature: mfI1CPqvBrgcXfgXMFjdNIhBf27ACE2YyeWsWV9ZI7T7RU0vHvbQpu9Z32ogzc+k8ZC5n3kz7h70eWKjgqNdKQF0eRp8mVKlmfzMLBVHbssB9jEZEDXThOX1XFqX7s7ymia1hoHQxQagPGzkdWxtlZPZ4ZPvr1RiqkgAu6Is8MZgXXrRoBKqjmSdrP1N7uxzJ/cjfSiis9FiLjuADoqmQ1P7p2N876YPAol7Rn0+GswwAwxldbdLrmVSjfytfSBJFqTMHn4itojgxSWWN1byuckQt8hSTEv/Lg97QoeGniYP17T80pJeQyL3b+295FPHSO2AtvCgyIbKMZ0BALilAA==13Wechatpay-Timestamp: 172285042114Wechatpay-Serial: 4DF076AC5A7D968D4A8B0B9C599A74CB4CF8EE8A15Wechatpay-Signature-Type: WECHATPAY2-SHA256-RSA20481617{"code_url":"weixin://wxpay/bizpayurl?pr=JyC91EIz1"}
(1)請從應(yīng)答或通知回調(diào)中獲取以下信息:
- HTTP 頭
Wechatpay-Timestamp
中的應(yīng)答時間戳 - HTTP 頭
Wechatpay-Nonce
中的應(yīng)答隨機(jī)串 - 應(yīng)答報文主體(Response Body),請使用原始報文主體執(zhí)行驗(yàn)簽。如果您使用了某個框架,要確保它不會篡改報文主體。對報文主體的任何篡改都會導(dǎo)致驗(yàn)證失敗。
(2)然后,請按照以下規(guī)則構(gòu)造應(yīng)答的驗(yàn)簽名串。簽名串共有三行,行尾以\n
結(jié)束,包括最后一行。\n
為換行符(ASCII 編碼值為 0x0A)。若應(yīng)答報文主體為空(如 HTTP 狀態(tài)碼為204 No Content
),最后一行僅為一個\n
換行符。
1應(yīng)答時間戳\n2應(yīng)答隨機(jī)串\n3應(yīng)答報文主體\n
則驗(yàn)簽名串為
11722850421\n2d824f2e086d3c1df967785d13fcd22ef\n3{"code_url":"weixin://wxpay/bizpayurl?pr=JyC91EIz1"}\n
# 3.獲取應(yīng)答簽名
微信支付的應(yīng)答簽名通過 HTTP 頭Wechatpay-Signature
傳遞。(請注意,示例可能存在換行,實(shí)際數(shù)據(jù)應(yīng)在一行)
1Wechatpay-Signature: mfI1CPqvBrgcXfgXMFjdNIhBf27ACE2YyeWsWV9ZI7T7RU0vHvbQpu9Z32ogzc+k8ZC5n3kz7h70eWKjgqNdKQF0eRp8mVKlmfzMLBVHbssB9jEZEDXThOX1XFqX7s7ymia1hoHQxQagPGzkdWxtlZPZ4ZPvr1RiqkgAu6Is8MZgXXrRoBKqjmSdrP1N7uxzJ/cjfSiis9FiLjuADoqmQ1P7p2N876YPAol7Rn0+GswwAwxldbdLrmVSjfytfSBJFqTMHn4itojgxSWWN1byuckQt8hSTEv/Lg97QoeGniYP17T80pJeQyL3b+295FPHSO2AtvCgyIbKMZ0BALilAA==
使用 base64 解碼Wechatpay-Signature
字段值,得到應(yīng)答簽名。
提示
某些代理服務(wù)器或 CDN 服務(wù)提供商,在轉(zhuǎn)發(fā)時可能會“過濾”微信支付擴(kuò)展的 HTTP 頭,導(dǎo)致應(yīng)用層無法獲取微信支付的簽名信息。商戶遇到這種情況時,我們建議嘗試調(diào)整代理服務(wù)器配置,或者通過直連的方式訪問微信支付的服務(wù)器和接收通知回調(diào)。
# 4.驗(yàn)證簽名
很多編程語言的簽名驗(yàn)證函數(shù)支持對驗(yàn)簽名串和簽名進(jìn)行簽名驗(yàn)證。強(qiáng)烈建議商戶調(diào)用該類函數(shù),使用微信支付平臺公鑰對驗(yàn)簽名串和簽名進(jìn)行 SHA256 with RSA 簽名驗(yàn)證。
下面展示使用命令行演示如何進(jìn)行驗(yàn)簽。這里已經(jīng)獲取了平臺證書并保存為1900009191_wxp_cert.pem
,你可以直接將以下平臺證書公鑰保存到本地用于操作驗(yàn)證。
1、首先,從微信支付平臺證書導(dǎo)出微信支付平臺公鑰。
1$ openssl x509 -in 1900009191_wxp_cert.pem -pubkey -noout > 1900009191_wxp_pub.pem2$ cat 1900009191_wxp_pub.pem3-----BEGIN PUBLIC KEY-----4MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwXNI6sdlknHBnK8Fu2U65Cwor9qY747jP8KAfeBMeveEt1TqaHkLfaSD07trZLhGpfs8/AHqjhgSMO1O10YQW6OrrJ4hjIWPKqxbgrYMkBQc+mwdiWp4W3ByCqxBRagCveCXRWCmuJYovl9H/bsDI07iGbpVtEOghJtfciisYSgxcLufUDTRkvwxjIBK1pCRjk33jJ5YTBWTHMRtMAOcFLN8F6hdEYdX8SPsgHHeLZ5Lv2T/686w1xtgCHef/sd4uSfWmyzsalQdHG/e4IyYmrhx9+O3VBoNDzE3nx23bFeV/RVNCG7cV6VhmYokJNHa/erIPkEmEFID6A5wQOXuxUkmJ10WwIDAQAB11-----END PUBLIC KEY-----
提示
Java支持使用證書初始化簽名對象,詳見initVerify(Certificate) (opens new window),并不需要先導(dǎo)出公鑰。
2、然后,使用 base64 解碼應(yīng)答簽名,將保存為文件 signature.txt
。(以下命令行均在一行)
1openssl base64 -d <<< 'mfI1CPqvBrgcXfgXMFjdNIhBf27ACE2YyeWsWV9ZI7T7RU0vHvbQpu9Z32ogzc+k8ZC5n3kz7h70eWKjgqNdKQF0eRp8mVKlmfzMLBVHbssB9jEZEDXThOX1XFqX7s7ymia1hoHQxQagPGzkdWxtlZPZ4ZPvr1RiqkgAu6Is8MZgXXrRoBKqjmSdrP1N7uxzJ/cjfSiis9FiLjuADoqmQ1P7p2N876YPAol7Rn0+GswwAwxldbdLrmVSjfytfSBJFqTMHn4itojgxSWWN1byuckQt8hSTEv/Lg97QoeGniYP17T80pJeQyL3b+295FPHSO2AtvCgyIbKMZ0BALilAA==' > signature.txt
3、最后,驗(yàn)證簽名,得到驗(yàn)簽結(jié)果,請確認(rèn)你的結(jié)果和文檔的結(jié)果一致,如果驗(yàn)簽結(jié)果是Verification Failure,請確認(rèn)是否獲取到了正確的平臺證書的公鑰或者驗(yàn)簽串是否有嚴(yán)格按照文檔格式換行
1$ openssl dgst -sha256 -verify 1900009191_wxp_pub.pem -signature signature.txt << EOF217228504213d824f2e086d3c1df967785d13fcd22ef4{"code_url":"weixin://wxpay/bizpayurl?pr=JyC91EIz1"}5EOF
1Verified OK
# 5. 應(yīng)對簽名探測流量
為了確保商戶系統(tǒng)的安全,微信支付會在極少數(shù)應(yīng)答或通知回調(diào)中生成錯誤簽名,以探測商戶系統(tǒng)是否正確地驗(yàn)證了簽名。
商戶系統(tǒng)不應(yīng)對探測流量進(jìn)行特殊處理,而應(yīng)將其視為正常的應(yīng)答或通知回調(diào),并對其簽名進(jìn)行驗(yàn)證。
在排查問題時,您可以通過查看簽名值中的 WECHATPAY/SIGNTEST/
前綴快速判斷是否為探測流量。所有用于探測目的的簽名值都會包含此前綴。
在驗(yàn)簽失敗的情況下,我們建議商戶系統(tǒng)采取以下措施:
- 如果應(yīng)答的簽名驗(yàn)證失敗,商戶系統(tǒng)應(yīng)舍棄該應(yīng)答。為了提高用戶體驗(yàn),商戶系統(tǒng)可以適當(dāng)?shù)刂卦嚕蛘咦層脩糁匦掳l(fā)起請求。微信支付不會針對重試請求發(fā)起探測。
- 若通知回調(diào)的簽名驗(yàn)證失敗,商戶系統(tǒng)應(yīng)返回失敗(即應(yīng)答
4xx
或5xx
的狀態(tài)碼),等待微信支付攜帶正確簽名重新發(fā)送通知回調(diào)。
如果你有關(guān)于簽名探測任何疑問,請通過在線技術(shù)咨詢 (opens new window)聯(lián)系我們的技術(shù)支持。