支付網關接入中的ssl連接和簽名調試tips

博客原文傳送門:支付網關接入中的ssl連接和簽名調試tips


支付平臺網關接入是個費力不討好的活。做過的人都明白,本身沒有很高的技術含量,但是工作的內容是及其繁瑣和費時費力的。對一個商家的支付平臺的開發者而言,每一個bank processor的接入都會涉及到基本的支付機構接入文檔閱讀,基本支付用例分析,雙方通信方式,消息格式,連接和加密方式等分析。山人也曾接入過目前主流的幾家支付渠道,便整理了些有用的tips以備不時之需。

一 ssl連接

目前來看國內目前主流的仍然是基於B/S架構的Web Service模式。採用基於SSL加密下的HTTP協議。bank side 給出標準的請求方式(如GET或POST),相應的參數格式(如Json,XML, QueryString)等。因爲支付本身就對交易事務通訊的安全級別要求較高,故而ssl加密則是必須的。但由於前段時間openssl漏洞的巨大影響,很多網站對ssl加密祕鑰和證書的要去也越來越高。很多老的ssl協議已經不再支持。如alipay.com 網站的ssl協議已經不支持ssl2了。相應的加密支持的芯片級也有所升級。這些ssl連接的細節對於client連接都很重要。最近發現了一個分析一個網站ssl協議細節的網站,SSL Lab 其可以非常詳細的分析一個網站ssl連接細節。其不僅對於我們分析ssl的安全性非常重要,也是我們做支付網關接入的有利參考。
ssl連接的認證方式分爲單向認證和雙向認證。前者指的是往往只有客戶端認證服務器證書,而服務器不會認證客戶端證書。支付網關中的大多數商家,如支付寶,Payease,CMB等其實都是單向認證的方式。而後者則是指不僅客戶端要認證服務器的證書,服務器邊也要認證客戶端證書。

a- 服務器證書

服務器證書是服務提供商在虛擬網絡的身份證明。通過權威的第三方的CA(Cerfitication Authority)機構來註冊。最常用的有GeoTrust,VerifiSign等。如Amazon,Alipay等採用均是VerifiSign頒發的證書。而銀聯則是採用GeoTrust的證書。通常而言,這些機構採用比較權威的認證方式,流程相對來說比較繁瑣,也價格不菲。於是也有一些機構採用自自簽名的證書,最廣爲所知道的應該是12306了吧。
查看一個服務器的根證書可以通過如下命令:

openssl s_client -connect payment.ebank.cmbchina.com:443 -showcerts   

如果想下載一個服務器的證書,可以直接在瀏覽器裏點擊URL最左側的小鎖標誌的查看證書信息,然後到相應瀏覽器的證書管理setting裏下載即可。如山人下載的amazon.cn的verifySign簽名的證書  如果想下載作爲demo演示點擊此處。ssl證書是標準的x509格式,包含頒發者和授予者的信息,證書籤名算法和公鑰。從證書中提取公鑰:

openssl x509 -pubkey -noout -in cert.pem  > pubkey.pem

對於自簽名的證書,可以通過openssl先生成祕鑰,然後創建證書請求文件,在自己給自己簽名:

openssl genrsa -out prvtkey.pem 1024/2048   # create key
openssl req -new -key prvtkey.pem -out cert.csr   # create cert request
openssl req -new -x509 -key prvtkey.pem -out cacert.pem -days 1095  # generate ca cert

b- 客戶端證書

如果一個服務器只允許特定的客戶端訪問,便可以通過向制定客戶頒發唯一標識該客戶身份的客戶端證書。對於單向認證的服務器,不需要客戶端證書,只需要把獲取到的服務器證書安裝到制定證書目錄便可以實現認證服務器。
雙向認證過程
如Java裏重要用trustStore來存儲服務器證書。可以用keytool命令來創建一個trustStore文件,

keytool -import -file C:\cascerts\firstCA.cert -alias firstCA -keystore myTrustStore

然後把獲取到的服務器根證書import到trustStore裏:

keytool -import -trustcacerts -file cacert.pem.cer -alias tenpay_ca -keystore wechat-cert.ssl.truststore.jks
keytool -list -v -keystore  $JAVA_HOME/jre/lib/security/cacerts

如果安裝客戶端證書則創建一個keyStore(命令跟上面一樣),然後實現客戶端的認證。如果要改變keyStore的密碼,

keytool -storepasswd -keystore my.keystore  #Change a keystore password.
keytool -keypasswd  -alias <key_name> -keystore my.keystore   #Change the key's password

證書有多種格式,最常見的如pem格式和pfx格式。國內很多支付機構的客戶端證書往往採用pfx(或者p12後綴,其實裏面格式都是PKCS#12標準)。從pfx格式轉換成pem格式可以通過如下命令:

openssl pkcs12 -in acp700000000000001.pfx -out prikey.pem -nocerts   # pfx -> pem
openssl x509 -in mycert.crt -out mycert.pem -outform PEM    # crt -> pem

通常客戶端的pfx格式的證書還包括私鑰,從pfx中提取私鑰如下:

openssl pkcs12 -in publicAndprivate.pfx -nocerts -out privateKey.pem

二 加密簽名算法

ssl協議實現了連接層的加密,通常支付網關還要實現數據層的加密和簽名。如當客戶在亞馬遜選擇支付寶作爲支付方式時,亞馬遜會發起一筆支付請求到支付寶網關。其請求form中便包含支付參數和相應的簽名,從更細粒度確保支付請求確實是亞馬遜發起的。支付寶收到請求首先便是驗證其簽名是否正確。常用的加密算法如DSA, RSA等,摘要算法如SHA1,MD5等。由於最近安全事件越發增多,接入商家基本要求是RSA2048位的加密簽名標準。
加密和簽名是相對的過程。加密的過程是商家對發往銀行服務器端的請求用自己的私鑰加密,銀行端收到請求後,則用商家側實現給的公鑰進行驗籤。生成響應後,在用自己側的私鑰進行簽名,商家在收到銀行側的響應信息後用銀行實現提供的公鑰進行驗證。簽名保證的是信心來源的真實性,因爲商家是唯一擁有自己私鑰的人,當銀行側驗證簽名正確時,就表示這條信心確實是從商家發來的。因此其可以保證信息不被篡改,但並不能保證信息不被竊聽。加密則是通過重新編碼明文信息,來保證信息不被竊聽。加密的過程是商家用自己的公鑰進行加密請求,銀行側收到後用商傢俬鑰給的私鑰進行解密。然後銀行用自己的公鑰進行響應的加密,商家收到後用銀行提供的私鑰進行解密。 因爲國內大多依賴ssl層來進行數據加密,因此實際的網關接入中多僅僅使用簽名。最常用的簽名算法如MD5,SHA1,SHA1WithRSA等。

a- 簽名和驗簽過程

針對對稱和非對稱的算法,簽名和驗籤的過程有所不同。對於MD5,SHA1等對稱算法,通常按照原始參數的key value pair的形式構造待簽名的plain text,值得注意的是則裏的原始串指的是非經過URLEncode的原始鍵值對。且通常空值和sign_key等是不參與簽名過程,最後把簽名得到的signature,構造成鍵值對附在請求參數上。在驗籤的過程用同樣的方法構造好待簽名的plain text串,把得到的簽名後請求傳來的參數進行對比即可。而非對稱的簽名則是構造好籤名的串,連同當前的簽名值一起傳入驗證簽名的算法。

b- 公私要生成和常用格式

RSA目前仍然是主流的簽名方法,通常用openssl來生成或提取RSA公私鑰。如生成2048位的私鑰對,

`openssl genrsa -out privatekey.txt 2048` 

從私鑰對中導出公鑰,

`openssl rsa -in key.pem -pubout -out pubkey.pem`。   

從PEM證書中提取公鑰,

openssl x509 -pubkey -noout -in cert.pem  > pubkey.pem

從私鑰生成證書,

openssl req -x509 -new -nodes -key rootCA.key -days 1024 -out rootCA.pem

PEM格式的RSA私鑰也有不同的格式 ,最常見的有兩種PKCS#1和PKCS#8 format,分別如下:

#Legacy PKCS#1 Format
-----BEGIN PRIVATE KEY-----
BASE64 ENCODED DATA
-----END PRIVATE KEY-----

#PKCS#8 Format
-----BEGIN RSA PRIVATE KEY-----
BASE64 ENCODED DATA
-----END RSA PRIVATE KEY-----

StackOverFlow上有個解釋兩者區別的經典回答:what-is-the-differences-between-begin-rsa-private-key-and-begin-private-key
簡單說來,PKCS#1格式僅僅是一個RSA key,等於PKCS#8中的RSA key對象。而PKCS#8不僅有PKCS#1所含有的RSA key對象,還包含版本算法標識。當然也可以從PKCS#1格式轉換成PKCS#8格式,命令如下:

openssl rsa -in begin_private_key.key -out begin_rsa_private_key.key

上面的命令總結只是結合支付網關調試過程中常用的命令,對於目前國內第三方支付機構和銀行的接入這些命令應該足夠了。以後有增加還會持續更新。
Song Long, and Thanks for All The Fish.

三 參考

[1]. WeChat API.
[2]. 支付寶開放平臺.


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章