四、公鑰和私鑰,加密和數(shù)字簽名

目錄

一、名詞解釋
?1、什么是公鑰和私鑰
?2、什么是加密和數(shù)字簽名
二、支付寶SDK支付流程解釋
?1、一些關(guān)鍵詞
?2、支付寶支付流程
?3、服務(wù)端對(duì)訂單信息加簽和對(duì)支付結(jié)果驗(yàn)簽的簡(jiǎn)單演示


本文涉及到支付寶SDK的內(nèi)容,均摘自支付寶開(kāi)放平臺(tái)。

因?yàn)橹Ц秾歋DK使用RSA來(lái)加密和生成數(shù)字簽名,所以本文中涉及到的概念也都是針對(duì)于RSA的。



一、名詞解釋


1、什么是公鑰和私鑰

一對(duì)兒密鑰生成后,會(huì)有公鑰和私鑰之分,我們需要把私鑰保存下來(lái),而把公鑰發(fā)布出去。一對(duì)兒公鑰和私鑰,不能由其中一個(gè)導(dǎo)出另一個(gè)。

比如使用支付寶SDK的時(shí)候,我們商戶端會(huì)生成一對(duì)兒密鑰A和B,A是私鑰,B是公鑰,支付寶也會(huì)生成一對(duì)兒密鑰C和D,C是私鑰,D是公鑰。我們商戶端需要把商戶端私鑰A保存下來(lái),而把商戶端公鑰B發(fā)布出去給支付寶,支付寶需要把支付寶私鑰C保存下來(lái),而把支付寶公鑰D發(fā)布出去給我們商戶端。

2、什么是加密和數(shù)字簽名

加密是指我們使用一對(duì)兒密鑰中的一個(gè)來(lái)對(duì)數(shù)據(jù)加密,而使用另一個(gè)來(lái)對(duì)數(shù)據(jù)解密的技術(shù),需要注意的是公鑰和私鑰都可以用來(lái)加密,也都可以用來(lái)解密,并不是規(guī)定死了只能用公鑰加密私鑰解密,但是加解密必須是一對(duì)兒密鑰之間的互相加解密,否則不能成功。

加密的目的是為了保證數(shù)據(jù)的不可讀性,防止數(shù)據(jù)在傳輸過(guò)程中被截獲。

知道了加密這個(gè)概念,我們先看一下支付寶的加密過(guò)程,再引出數(shù)字簽名這個(gè)概念。接著第1小節(jié)的例子,當(dāng)我們商戶端和支付寶互相發(fā)布了公鑰之后,我們商戶端手里就有商戶端私鑰支付寶公鑰兩個(gè)密鑰,支付寶手里也有商戶端公鑰支付寶私鑰兩個(gè)密鑰?,F(xiàn)在假設(shè)我們商戶端要給支付寶傳輸訂單信息,那么為了保證傳輸訂單信息時(shí)數(shù)據(jù)的安全性,結(jié)合我們商戶端手里所擁有的密鑰,可以有兩套加密方案

  • 方案一:
    (商戶端)明文訂單信息 + 商戶端私鑰加密 = 加密訂單信息
    (--->網(wǎng)絡(luò)傳輸--->)
    (支付寶)加密訂單信息 + 商戶端公鑰解密 = 明文訂單信息

  • 方案二:
    (商戶端)明文訂單信息 + 支付寶公鑰加密 = 加密訂單信息
    (--->網(wǎng)絡(luò)傳輸--->)
    (支付寶)加密訂單信息 + 支付寶私鑰解密 = 明文訂單信息

貌似這兩套加密方案都能達(dá)到對(duì)訂單信息加密的效果,而且如果采用方案二,我們商戶端甚至只需要存儲(chǔ)支付寶公鑰這一個(gè)密鑰,都不用去申請(qǐng)一對(duì)兒商戶端的公私鑰來(lái)維護(hù),支付寶也不用保存我們一堆商戶那么多的商戶端公鑰了,這不是更簡(jiǎn)單嗎,那為什么支付寶開(kāi)放平臺(tái)讓我們采用的是方案一而不是方案二呢?下面來(lái)回答一下。

支付寶開(kāi)放平臺(tái)說(shuō)明:當(dāng)我們采用RSA(1024位密鑰)來(lái)加密的時(shí)候,支付寶分配給所有商戶的支付寶公鑰都是一樣的,即支付寶針對(duì)那么多的商戶只負(fù)責(zé)維護(hù)一對(duì)兒支付寶公私鑰,這就意味著支付寶公鑰隨便什么人拿到后都是一樣的;而當(dāng)我們采用RSA2(2048位密鑰)來(lái)加密的時(shí)候,支付寶會(huì)分配給每個(gè)商戶單獨(dú)的一個(gè)支付寶公鑰,即支付寶為每一個(gè)的商戶單獨(dú)的維護(hù)一對(duì)獨(dú)立的支付寶公私鑰,當(dāng)然一個(gè)商戶下的多個(gè)App的支付寶公鑰是一樣的。RSA是早就支持的,RSA2是最近才支持的。

知道了上面這段話,現(xiàn)在假設(shè)我們采用的是方案二,并且采用RSA加密(很多老業(yè)務(wù)并沒(méi)有使用RSA2加密),業(yè)務(wù)邏輯將會(huì)是下面這樣。

這就出問(wèn)題了,RSA加密下,支付寶公鑰是公開(kāi)發(fā)布的,而且所有的商戶用的都是同一個(gè)支付寶公鑰(上面聲明了RSA2加密下,支付寶才針對(duì)每個(gè)商戶維護(hù)了一對(duì)兒公私鑰),攻擊者很容易就能獲取到,而notify_url也很容易被截獲,那攻擊者拿到這兩個(gè)東西就可以做和商戶一樣的操作來(lái)發(fā)起支付請(qǐng)求,這樣就會(huì)一直給小明充錢了。

所以支付寶就需要確認(rèn)支付請(qǐng)求確實(shí)是商戶發(fā)給他們的,而不是攻擊者發(fā)給他們的。這就用到了數(shù)字簽名,我們會(huì)通過(guò)方案一的實(shí)現(xiàn)流程來(lái)引出數(shù)字簽名的具體概念。如果我們采用的是方案一,我們商戶端保存的就是商戶端私鑰和支付寶公鑰,而支付寶保存的就是需要存著商戶端公鑰和支付寶私鑰的,業(yè)務(wù)邏輯將會(huì)是下面這樣。

這樣就可以保證交易的安全性了,我們也可以看出使用支付寶SDK保證交易的安全性注重的其實(shí)不是訂單信息是否加密,而是如何確保商戶端和支付寶能夠互相確認(rèn)身份,訂單信息是明文的,但是后面拼接了數(shù)字簽名。

數(shù)字簽名其實(shí)就是明文數(shù)據(jù)加密之后得到的一個(gè)密文,只不過(guò)它是用私鑰加密生成的而已,我們一般會(huì)把數(shù)字簽名拼接在明文數(shù)據(jù)后面一起傳遞給接收方,接收方收到后用公鑰解密數(shù)字簽名,從而驗(yàn)證發(fā)送方的身份、以及明文數(shù)據(jù)是否被篡改。數(shù)字簽名的生成過(guò)程其實(shí)就是一個(gè)加密過(guò)程,數(shù)字簽名的驗(yàn)簽過(guò)程就是一個(gè)解密過(guò)程。

數(shù)字簽名的目的有兩個(gè):一、發(fā)送方和接收方互相驗(yàn)證身份;二、驗(yàn)證數(shù)據(jù)是否被篡改。

加密和數(shù)字簽名可以單獨(dú)使用,當(dāng)然也可以共同使用來(lái)完成數(shù)據(jù)的安全傳輸。


二、支付寶SDK支付流程解釋


從上面第一部分我們知道為了確保商戶和支付寶交易的安全性,約定采用的是給訂單信息加數(shù)字簽名傳輸?shù)姆绞?。支付寶也為我們提供?a target="_blank">一鍵生成RSA密鑰的工具,可以幫助我們很快的生成一對(duì)商戶端公私鑰。以下會(huì)對(duì)支付寶SDK的支付流程做個(gè)大概的解釋,并點(diǎn)出實(shí)際開(kāi)發(fā)中我們使用支付寶SDK時(shí)應(yīng)該注意的地方。

1、一些關(guān)鍵詞

  • 商戶端私鑰

由我們商戶端自己生成的RSA私鑰(必須與商戶端公鑰是一對(duì)),生成后要保存在服務(wù)端,絕對(duì)不能保存在客戶端,也絕對(duì)不能從服務(wù)端傳輸給客戶端。

用來(lái)對(duì)訂單信息加簽,加簽過(guò)程一定要在服務(wù)端完成,絕對(duì)不能在客戶端做加,客戶端只負(fù)責(zé)用加簽后的訂單信息調(diào)起支付寶來(lái)支付。

  • 商戶端公鑰

由我們商戶端自己生成的RSA公鑰(必須與商戶端私鑰是一對(duì)),生成后需要填寫在支付寶開(kāi)放平臺(tái)。

用來(lái)給支付寶服務(wù)端驗(yàn)簽經(jīng)過(guò)我們加簽后的訂單信息,以確保訂單信息確實(shí)是我們商戶端發(fā)給支付寶的,并且確保訂單信息在傳輸過(guò)程中未被篡改。

  • 支付寶私鑰

這個(gè)和我們就沒(méi)關(guān)系了,支付寶私鑰是他們自己生成的,也是他們自己保存的。

用來(lái)對(duì)支付結(jié)果進(jìn)行加簽。

  • 支付寶公鑰

支付寶公鑰和支付寶私鑰是一對(duì),也是支付寶生成的,當(dāng)我們把商戶端公鑰填寫在支付寶開(kāi)放平臺(tái)后,平臺(tái)就會(huì)給我們生成一個(gè)支付寶公鑰,我們可以復(fù)制下來(lái)保存在服務(wù)端,同樣不要保存在客戶端,并且不要傳輸給客戶端。

用來(lái)讓服務(wù)端對(duì)支付寶服務(wù)端返給我們的同步或異步支付結(jié)果進(jìn)行驗(yàn)簽,以確保支付結(jié)果確實(shí)是由支付寶服務(wù)端返給我們服務(wù)端的,而且沒(méi)有被篡改,對(duì)支付結(jié)果的驗(yàn)簽工作也一定要在服務(wù)端完成。

2、支付寶SDK的支付流程

支付寶支付流程時(shí)序圖
  • 第1步:用戶在我們客戶端里選擇好訂單信息后(比如要充值11塊錢),然后選擇支付寶支付;

  • 第2步:我們客戶端會(huì)走個(gè)接口告訴服務(wù)端用戶是選擇了哪個(gè)訂單信息,服務(wù)端收到請(qǐng)求后,就會(huì)使用商戶端私鑰對(duì)這個(gè)訂單信息進(jìn)行加密生成數(shù)字簽名,然后把這個(gè)數(shù)字簽名拼接在明文訂單信息后,形成一個(gè)加簽訂單信息orderString;(下面會(huì)用客戶端的代碼來(lái)簡(jiǎn)單演示一下這個(gè)加簽的過(guò)程,讓我們看到訂單信息是如何通過(guò)加簽最終轉(zhuǎn)變?yōu)檎{(diào)起支付寶那個(gè)orderString的)

  • 第3步:服務(wù)端通過(guò)第2步那個(gè)接口把orderString返回給客戶端;

  • 第4步、第5步:客戶端使用這個(gè)orderString調(diào)用一下支付寶SDK的提供的支付API發(fā)起支付就可以調(diào)起支付寶客戶端來(lái)支付了,與此同時(shí)當(dāng)然支付寶服務(wù)端也收到了這個(gè)支付請(qǐng)求;

  • 第6步:支付寶服務(wù)端收到這個(gè)orderString后就會(huì)使用我們填寫在支付寶開(kāi)放平臺(tái)的那個(gè)商戶端公鑰對(duì)這個(gè)加簽訂單信息進(jìn)行驗(yàn)簽,并處理交易來(lái)完成支付,然后就會(huì)得到一個(gè)交易結(jié)果(交易成功啊、失敗啊、中途取消啊等等),支付寶服務(wù)端又會(huì)使用支付寶私鑰對(duì)這個(gè)交易結(jié)果進(jìn)行加簽;(支付寶服務(wù)端的加簽、驗(yàn)簽操作和我們服務(wù)端做的加簽、驗(yàn)簽操作是類似的)

  • 第7、8、9、10步: (實(shí)際開(kāi)發(fā)中會(huì)忽略掉9、10步,這里只是說(shuō)明它們?cè)诟墒裁矗?/strong>支付寶服務(wù)端會(huì)把這個(gè)加簽后的交易結(jié)果同步的返回給我們客戶端,然后我們客戶端需要把這個(gè)加簽交易結(jié)果返回給服務(wù)端去驗(yàn)簽(注意千萬(wàn)不能在客戶端驗(yàn)簽,倒不是說(shuō)不能在客戶端驗(yàn)簽,主要的意思是說(shuō)不要把支付寶公鑰存在客戶端),服務(wù)端驗(yàn)簽結(jié)束后把真正的支付結(jié)果返回給我們客戶端,客戶端根據(jù)這個(gè)支付結(jié)果作出相應(yīng)的界面處理。但是,支付寶開(kāi)放平臺(tái)說(shuō)了:

    • 1、強(qiáng)烈建議我們開(kāi)發(fā)者直接依賴支付寶服務(wù)端返回給我們服務(wù)端的異步支付結(jié)果(即第12步),而忽略同步支付結(jié)果,因?yàn)檫@個(gè)同步支付結(jié)果有可能收不到啊,比如我們App在調(diào)用支付寶支付的過(guò)程中突然閃退了,那這個(gè)同步支付結(jié)果我們App是收不到的,自然也就無(wú)法傳給服務(wù)端去驗(yàn)簽,那不就完?duì)僮恿寺?,但是異步支付結(jié)果支付寶服務(wù)端是肯定能確保返回給我們的服務(wù)端的;
    • 2、但是同步的支付結(jié)果和異步的支付結(jié)果都可以作為支付完成的憑證,所以為了簡(jiǎn)化集成流程,我們客戶端就可以直接將同步支付結(jié)果作為支付結(jié)束的一個(gè)憑證,在忽略掉第7、8、9、10步的基礎(chǔ)上,直接根據(jù)同步支付結(jié)果的狀態(tài)碼來(lái)作出相應(yīng)的界面處理,甚至都不去關(guān)心支付結(jié)果的具體信息,而真正改變用戶金錢字段的業(yè)務(wù)操作則由服務(wù)端根據(jù)異步的支付信息經(jīng)過(guò)驗(yàn)簽后去做改變,當(dāng)然如果服務(wù)端驗(yàn)簽失敗了就說(shuō)明支付結(jié)果被篡改了,是要報(bào)警的^_。
  • 第11步:客戶端直接將同步支付結(jié)果作為支付結(jié)束的一個(gè)憑證,根據(jù)狀態(tài)碼來(lái)作出相應(yīng)的界面處理;

  • 第12步、第13步:在第6步結(jié)束后,支付寶服務(wù)端會(huì)異步的把加簽支付結(jié)果返回給我們服務(wù)端,服務(wù)端用支付寶公鑰對(duì)這個(gè)支付結(jié)果進(jìn)行驗(yàn)簽,驗(yàn)簽后根據(jù)支付結(jié)果作出實(shí)際的業(yè)務(wù)處理(如支付成功則給用戶的金錢字段加上11,如果失敗則不做處理等等);第13步是服務(wù)端會(huì)把實(shí)際的業(yè)務(wù)處理完畢后還需要在他們服務(wù)端SDK的回調(diào)里把業(yè)務(wù)的處理結(jié)果返回給支付寶服務(wù)端(如實(shí)際業(yè)務(wù)處理成功就返回給支付寶服務(wù)端success就算結(jié)束本次交易,如實(shí)際業(yè)務(wù)處理失敗就返回給支付寶服務(wù)端fail,支付寶服務(wù)端就去再次調(diào)用服務(wù)端SDK來(lái)重新處理實(shí)際的業(yè)務(wù)邏輯直到成功,如果超過(guò)了一定的次數(shù),服務(wù)端還是給支付寶服務(wù)端返回fail,說(shuō)明是我們的系統(tǒng)出了問(wèn)題,支付寶服務(wù)端就不會(huì)再觸發(fā)服務(wù)端SDK來(lái)重新處理實(shí)際的業(yè)務(wù)了,這種情況下咱們的客戶就會(huì)打我們的客服了,說(shuō)我的支付寶都扣錢了,但為什么沒(méi)充值成功呢,我們就人工的給人家處理一下)。

3、服務(wù)端對(duì)訂單信息加簽和對(duì)支付結(jié)果驗(yàn)簽的簡(jiǎn)單演示

上面已經(jīng)說(shuō)過(guò)了:訂單信息的加簽和支付結(jié)果的驗(yàn)簽是一定要在服務(wù)端做的,絕對(duì)不能在客戶端做。

3.1 服務(wù)端對(duì)訂單信息加簽的簡(jiǎn)單演示

下面是在客戶端對(duì)訂單信息加簽的過(guò)程,僅僅是為了模擬服務(wù)端來(lái)表明訂單信息是如何通過(guò)加簽最終轉(zhuǎn)變?yōu)閛rderString的,千萬(wàn)不要覺(jué)得訂單信息的加簽過(guò)程也可以放在客戶端完成。

  • 第1步:用AppID、簽名類型、商品標(biāo)題、商品描述、商品價(jià)格啊等一些信息,構(gòu)建一個(gè)支付寶SDK提供的訂單信息類的實(shí)體,如:

//將商品信息賦予AlixPayOrder的成員變量
Order* order = [Order new];

// NOTE: app_id設(shè)置
order.app_id = appID;

// NOTE: 支付接口名稱
order.method = @"alipay.trade.app.pay";

// NOTE: 參數(shù)編碼格式
order.charset = @"utf-8";

// NOTE: 當(dāng)前時(shí)間點(diǎn)
NSDateFormatter* formatter = [NSDateFormatter new];
[formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
order.timestamp = [formatter stringFromDate:[NSDate date]];

// NOTE: 支付版本
order.version = @"1.0";

// NOTE: sign_type設(shè)置
order.sign_type = @"RSA";

// NOTE: 商品數(shù)據(jù)
order.biz_content = [BizContent new];
order.biz_content.body = @"我是測(cè)試數(shù)據(jù)";
order.biz_content.subject = @"1";
order.biz_content.out_trade_no = [self generateTradeNO]; //訂單ID(由商家自行制定)
order.biz_content.timeout_express = @"30m"; //超時(shí)時(shí)間設(shè)置
order.biz_content.total_amount = [NSString stringWithFormat:@"%.2f", 0.01]; //商品價(jià)格

  • 第2步:使用支付寶SDK提供的API,把第一步構(gòu)建的訂單信息實(shí)體轉(zhuǎn)換成一個(gè)訂單信息字符串,轉(zhuǎn)換后會(huì)是一個(gè)類似下面這樣的字符串:

app_id=2015052600090779&biz_content={"timeout_express":"30m","seller_id":"","product_code":"QUICK_MSECURITY_PAY","total_amount":"0.02","subject":"1","body":"我是測(cè)試數(shù)據(jù)","out_trade_no":"ZQLM3O56MJD4SK3"}&charset=utf-8&method=alipay.trade.app.pay&sign_type=RSA2&timestamp=2016-07-28 20:36:11&version=1.0

  • 第3步:調(diào)用支付寶SDK提供的API,用客戶端私鑰對(duì)第2步生成的訂單信息字符串進(jìn)行加密生成數(shù)字簽名,生成的數(shù)字簽名類似于下面醬式兒:

GsSZgPloF1vn52XAItRAldwQAbzIgkDyByCxMfTZG%2FMapRoyrNIJo4U1LUGjHp6gdBZ7U8jA1kljLPqkeGv8MZigd3kH25V0UK3Jc3C94Ngxm5S%2Fz5QsNr6wnqNY9sx%2Bw6DqNdEQnnks7PKvvU0zgsynip50lAhJmflmfHvp%2Bgk%3D

  • 第4步:按照支付寶規(guī)定的格式要求,把數(shù)字簽名拼接在原明文訂單信息字符串的后面就形成了最終能夠調(diào)起支付寶支付的那個(gè)加簽訂單信息--orderString,類似于下面這樣:

app_id=2015052600090779&biz_content={"timeout_express":"30m","seller_id":"","product_code":"QUICK_MSECURITY_PAY","total_amount":"0.02","subject":"1","body":"我是測(cè)試數(shù)據(jù)","out_trade_no":"ZQLM3O56MJD4SK3"}&charset=utf-8&method=alipay.trade.app.pay&sign_type=RSA2&timestamp=2016-07-28 20:36:11&version=1.0&sign=GsSZgPloF1vn52XAItRAldwQAbzIgkDyByCxMfTZG%2FMapRoyrNIJo4U1LUGjHp6gdBZ7U8jA1kljLPqkeGv8MZigd3kH25V0UK3Jc3C94Ngxm5S%2Fz5QsNr6wnqNY9sx%2Bw6DqNdEQnnks7PKvvU0zgsynip50lAhJmflmfHvp%2Bgk%3D

3.2 對(duì)支付結(jié)果驗(yàn)簽的簡(jiǎn)單演示

假設(shè)我們服務(wù)端收到了來(lái)自支付寶服務(wù)端的支付結(jié)果,即:支付結(jié)果+數(shù)字簽名

那么我們服務(wù)端就會(huì)對(duì)支付結(jié)果進(jìn)行驗(yàn)簽,怎么個(gè)驗(yàn)法呢?

  • 首先,服務(wù)端會(huì)把數(shù)字簽名截取下來(lái),用支付寶公鑰把數(shù)字簽名給它解密,如果能解密就可以確定確實(shí)是支付寶發(fā)給我們服務(wù)端的支付結(jié)果,如果解不了就說(shuō)明不是支付寶發(fā)給我們的支付結(jié)果,該報(bào)警就報(bào)警;

  • 然后,如果解密成功了,服務(wù)端還需要把解密后得到的明文支付結(jié)果和支付結(jié)果來(lái)做個(gè)對(duì)比,如果一樣則說(shuō)明是支付結(jié)果沒(méi)被篡改過(guò),如果不一樣則說(shuō)明支付結(jié)果中途被人篡改了,可以打110了。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容