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

目錄

一棉磨、名詞解釋
?1江掩、什么是公鑰和私鑰
?2、什么是加密和數(shù)字簽名
二乘瓤、支付寶SDK支付流程解釋
?1环形、一些關鍵詞
?2、支付寶支付流程
?3衙傀、服務端對訂單信息加簽和對支付結(jié)果驗簽的簡單演示


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

因為支付寶SDK使用RSA來加密和生成數(shù)字簽名统抬,所以本文中涉及到的概念也都是針對于RSA的火本。



一、名詞解釋


1蓄喇、什么是公鑰和私鑰

一對兒密鑰生成后发侵,會有公鑰和私鑰之分,我們需要把私鑰保存下來妆偏,而把公鑰發(fā)布出去刃鳄。一對兒公鑰和私鑰,不能由其中一個導出另一個钱骂。

比如使用支付寶SDK的時候叔锐,我們商戶端會生成一對兒密鑰A和B,A是私鑰见秽,B是公鑰愉烙,支付寶也會生成一對兒密鑰C和D,C是私鑰解取,D是公鑰步责。我們商戶端需要把商戶端私鑰A保存下來,而把商戶端公鑰B發(fā)布出去給支付寶禀苦,支付寶需要把支付寶私鑰C保存下來蔓肯,而把支付寶公鑰D發(fā)布出去給我們商戶端。

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

加密是指我們使用一對兒密鑰中的一個來對數(shù)據(jù)加密蔗包,而使用另一個來對數(shù)據(jù)解密的技術(shù),需要注意的是公鑰和私鑰都可以用來加密慧邮,也都可以用來解密调限,并不是規(guī)定死了只能用公鑰加密私鑰解密舟陆,但是加解密必須是一對兒密鑰之間的互相加解密,否則不能成功耻矮。

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

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

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

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

貌似這兩套加密方案都能達到對訂單信息加密的效果身辨,而且如果采用方案二,我們商戶端甚至只需要存儲支付寶公鑰這一個密鑰芍碧,都不用去申請一對兒商戶端的公私鑰來維護煌珊,支付寶也不用保存我們一堆商戶那么多的商戶端公鑰了,這不是更簡單嗎泌豆,那為什么支付寶開放平臺讓我們采用的是方案一而不是方案二呢定庵?下面來回答一下。

支付寶開放平臺說明:當我們采用RSA(1024位密鑰)來加密的時候踪危,支付寶分配給所有商戶的支付寶公鑰都是一樣的蔬浙,即支付寶針對那么多的商戶只負責維護一對兒支付寶公私鑰,這就意味著支付寶公鑰隨便什么人拿到后都是一樣的贞远;而當我們采用RSA2(2048位密鑰)來加密的時候畴博,支付寶會分配給每個商戶單獨的一個支付寶公鑰,即支付寶為每一個的商戶單獨的維護一對獨立的支付寶公私鑰蓝仲,當然一個商戶下的多個App的支付寶公鑰是一樣的俱病。RSA是早就支持的,RSA2是最近才支持的袱结。

知道了上面這段話亮隙,現(xiàn)在假設我們采用的是方案二,并且采用RSA加密(很多老業(yè)務并沒有使用RSA2加密)擎勘,業(yè)務邏輯將會是下面這樣咱揍。

這就出問題了颖榜,RSA加密下棚饵,支付寶公鑰是公開發(fā)布的煤裙,而且所有的商戶用的都是同一個支付寶公鑰(上面聲明了RSA2加密下,支付寶才針對每個商戶維護了一對兒公私鑰)噪漾,攻擊者很容易就能獲取到硼砰,而notify_url也很容易被截獲,那攻擊者拿到這兩個東西就可以做和商戶一樣的操作來發(fā)起支付請求欣硼,這樣就會一直給小明充錢了题翰。

所以支付寶就需要確認支付請求確實是商戶發(fā)給他們的,而不是攻擊者發(fā)給他們的诈胜。這就用到了數(shù)字簽名豹障,我們會通過方案一的實現(xiàn)流程來引出數(shù)字簽名的具體概念。如果我們采用的是方案一焦匈,我們商戶端保存的就是商戶端私鑰和支付寶公鑰血公,而支付寶保存的就是需要存著商戶端公鑰和支付寶私鑰的,業(yè)務邏輯將會是下面這樣缓熟。

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

數(shù)字簽名其實就是明文數(shù)據(jù)加密之后得到的一個密文彰触,只不過它是用私鑰加密生成的而已梯投,我們一般會把數(shù)字簽名拼接在明文數(shù)據(jù)后面一起傳遞給接收方,接收方收到后用公鑰解密數(shù)字簽名渴析,從而驗證發(fā)送方的身份晚伙、以及明文數(shù)據(jù)是否被篡改。數(shù)字簽名的生成過程其實就是一個加密過程俭茧,數(shù)字簽名的驗簽過程就是一個解密過程咆疗。

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

加密和數(shù)字簽名可以單獨使用毡们,當然也可以共同使用來完成數(shù)據(jù)的安全傳輸迅皇。


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


從上面第一部分我們知道為了確保商戶和支付寶交易的安全性衙熔,約定采用的是給訂單信息加數(shù)字簽名傳輸?shù)姆绞降峭恰VЦ秾氁矠槲覀兲峁┝?a target="_blank">一鍵生成RSA密鑰的工具,可以幫助我們很快的生成一對商戶端公私鑰红氯。以下會對支付寶SDK的支付流程做個大概的解釋框咙,并點出實際開發(fā)中我們使用支付寶SDK時應該注意的地方咕痛。

1、一些關鍵詞

  • 商戶端私鑰

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

用來對訂單信息加簽腔丧,加簽過程一定要在服務端完成,絕對不能在客戶端做加作烟,客戶端只負責用加簽后的訂單信息調(diào)起支付寶來支付愉粤。

  • 商戶端公鑰

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

用來給支付寶服務端驗簽經(jīng)過我們加簽后的訂單信息科汗,以確保訂單信息確實是我們商戶端發(fā)給支付寶的,并且確保訂單信息在傳輸過程中未被篡改绷雏。

  • 支付寶私鑰

這個和我們就沒關系了头滔,支付寶私鑰是他們自己生成的,也是他們自己保存的涎显。

用來對支付結(jié)果進行加簽坤检。

  • 支付寶公鑰

支付寶公鑰和支付寶私鑰是一對,也是支付寶生成的期吓,當我們把商戶端公鑰填寫在支付寶開放平臺后早歇,平臺就會給我們生成一個支付寶公鑰,我們可以復制下來保存在服務端讨勤,同樣不要保存在客戶端箭跳,并且不要傳輸給客戶端。

用來讓服務端對支付寶服務端返給我們的同步或異步支付結(jié)果進行驗簽潭千,以確保支付結(jié)果確實是由支付寶服務端返給我們服務端的谱姓,而且沒有被篡改,對支付結(jié)果的驗簽工作也一定要在服務端完成刨晴。

2屉来、支付寶SDK的支付流程

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

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

  • 第3步:服務端通過第2步那個接口把orderString返回給客戶端脐雪;

  • 第4步郭蕉、第5步:客戶端使用這個orderString調(diào)用一下支付寶SDK的提供的支付API發(fā)起支付就可以調(diào)起支付寶客戶端來支付了,與此同時當然支付寶服務端也收到了這個支付請求喂江;

  • 第6步:支付寶服務端收到這個orderString后就會使用我們填寫在支付寶開放平臺的那個商戶端公鑰對這個加簽訂單信息進行驗簽,并處理交易來完成支付旁振,然后就會得到一個交易結(jié)果(交易成功啊获询、失敗啊低淡、中途取消啊等等)论熙,支付寶服務端又會使用支付寶私鑰對這個交易結(jié)果進行加簽纬乍;(支付寶服務端的加簽志群、驗簽操作和我們服務端做的加簽胯舷、驗簽操作是類似的)

  • 第7察纯、8频蛔、9夫凸、10步: (實際開發(fā)中會忽略掉9甜攀、10步秋泄,這里只是說明它們在干什么)支付寶服務端會把這個加簽后的交易結(jié)果同步的返回給我們客戶端,然后我們客戶端需要把這個加簽交易結(jié)果返回給服務端去驗簽(注意千萬不能在客戶端驗簽规阀,倒不是說不能在客戶端驗簽恒序,主要的意思是說不要把支付寶公鑰存在客戶端),服務端驗簽結(jié)束后把真正的支付結(jié)果返回給我們客戶端谁撼,客戶端根據(jù)這個支付結(jié)果作出相應的界面處理歧胁。但是,支付寶開放平臺說了:

    • 1厉碟、強烈建議我們開發(fā)者直接依賴支付寶服務端返回給我們服務端的異步支付結(jié)果(即第12步)喊巍,而忽略同步支付結(jié)果,因為這個同步支付結(jié)果有可能收不到啊箍鼓,比如我們App在調(diào)用支付寶支付的過程中突然閃退了崭参,那這個同步支付結(jié)果我們App是收不到的,自然也就無法傳給服務端去驗簽款咖,那不就完犢子了嘛阵翎,但是異步支付結(jié)果支付寶服務端是肯定能確保返回給我們的服務端的;
    • 2之剧、但是同步的支付結(jié)果和異步的支付結(jié)果都可以作為支付完成的憑證郭卫,所以為了簡化集成流程,我們客戶端就可以直接將同步支付結(jié)果作為支付結(jié)束的一個憑證背稼,在忽略掉第7贰军、8、9、10步的基礎上词疼,直接根據(jù)同步支付結(jié)果的狀態(tài)碼來作出相應的界面處理俯树,甚至都不去關心支付結(jié)果的具體信息,而真正改變用戶金錢字段的業(yè)務操作則由服務端根據(jù)異步的支付信息經(jīng)過驗簽后去做改變贰盗,當然如果服務端驗簽失敗了就說明支付結(jié)果被篡改了许饿,是要報警的^_。
  • 第11步:客戶端直接將同步支付結(jié)果作為支付結(jié)束的一個憑證舵盈,根據(jù)狀態(tài)碼來作出相應的界面處理陋率;

  • 第12步、第13步:在第6步結(jié)束后秽晚,支付寶服務端會異步的把加簽支付結(jié)果返回給我們服務端瓦糟,服務端用支付寶公鑰對這個支付結(jié)果進行驗簽,驗簽后根據(jù)支付結(jié)果作出實際的業(yè)務處理(如支付成功則給用戶的金錢字段加上11赴蝇,如果失敗則不做處理等等)菩浙;第13步是服務端會把實際的業(yè)務處理完畢后還需要在他們服務端SDK的回調(diào)里把業(yè)務的處理結(jié)果返回給支付寶服務端(如實際業(yè)務處理成功就返回給支付寶服務端success就算結(jié)束本次交易,如實際業(yè)務處理失敗就返回給支付寶服務端fail句伶,支付寶服務端就去再次調(diào)用服務端SDK來重新處理實際的業(yè)務邏輯直到成功劲蜻,如果超過了一定的次數(shù),服務端還是給支付寶服務端返回fail考余,說明是我們的系統(tǒng)出了問題斋竞,支付寶服務端就不會再觸發(fā)服務端SDK來重新處理實際的業(yè)務了,這種情況下咱們的客戶就會打我們的客服了秃殉,說我的支付寶都扣錢了坝初,但為什么沒充值成功呢,我們就人工的給人家處理一下)钾军。

3鳄袍、服務端對訂單信息加簽和對支付結(jié)果驗簽的簡單演示

上面已經(jīng)說過了:訂單信息的加簽和支付結(jié)果的驗簽是一定要在服務端做的,絕對不能在客戶端做吏恭。

3.1 服務端對訂單信息加簽的簡單演示

下面是在客戶端對訂單信息加簽的過程拗小,僅僅是為了模擬服務端來表明訂單信息是如何通過加簽最終轉(zhuǎn)變?yōu)閛rderString的,千萬不要覺得訂單信息的加簽過程也可以放在客戶端完成樱哼。

  • 第1步:用AppID哀九、簽名類型、商品標題搅幅、商品描述阅束、商品價格啊等一些信息,構(gòu)建一個支付寶SDK提供的訂單信息類的實體茄唐,如:

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

// NOTE: app_id設置
order.app_id = appID;

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

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

// NOTE: 當前時間點
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設置
order.sign_type = @"RSA";

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

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

app_id=2015052600090779&biz_content={"timeout_express":"30m","seller_id":"","product_code":"QUICK_MSECURITY_PAY","total_amount":"0.02","subject":"1","body":"我是測試數(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,用客戶端私鑰對第2步生成的訂單信息字符串進行加密生成數(shù)字簽名呼盆,生成的數(shù)字簽名類似于下面醬式兒:

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

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

app_id=2015052600090779&biz_content={"timeout_express":"30m","seller_id":"","product_code":"QUICK_MSECURITY_PAY","total_amount":"0.02","subject":"1","body":"我是測試數(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 對支付結(jié)果驗簽的簡單演示

假設我們服務端收到了來自支付寶服務端的支付結(jié)果访圃,即:支付結(jié)果+數(shù)字簽名厨幻。

那么我們服務端就會對支付結(jié)果進行驗簽,怎么個驗法呢腿时?

  • 首先况脆,服務端會把數(shù)字簽名截取下來,用支付寶公鑰把數(shù)字簽名給它解密圈匆,如果能解密就可以確定確實是支付寶發(fā)給我們服務端的支付結(jié)果,如果解不了就說明不是支付寶發(fā)給我們的支付結(jié)果捏雌,該報警就報警跃赚;

  • 然后,如果解密成功了性湿,服務端還需要把解密后得到的明文支付結(jié)果和支付結(jié)果來做個對比纬傲,如果一樣則說明是支付結(jié)果沒被篡改過,如果不一樣則說明支付結(jié)果中途被人篡改了肤频,可以打110了叹括。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市宵荒,隨后出現(xiàn)的幾起案子汁雷,更是在濱河造成了極大的恐慌,老刑警劉巖报咳,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件侠讯,死亡現(xiàn)場離奇詭異,居然都是意外死亡暑刃,警方通過查閱死者的電腦和手機厢漩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來岩臣,“玉大人溜嗜,你說我怎么就攤上這事〖芑眩” “怎么了炸宵?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長谷扣。 經(jīng)常有香客問我焙压,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任涯曲,我火速辦了婚禮野哭,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘幻件。我一直安慰自己拨黔,他們只是感情好,可當我...
    茶點故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布绰沥。 她就那樣靜靜地躺著篱蝇,像睡著了一般。 火紅的嫁衣襯著肌膚如雪徽曲。 梳的紋絲不亂的頭發(fā)上零截,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天,我揣著相機與錄音秃臣,去河邊找鬼涧衙。 笑死,一個胖子當著我的面吹牛奥此,可吹牛的內(nèi)容都是我干的弧哎。 我是一名探鬼主播,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼稚虎,長吁一口氣:“原來是場噩夢啊……” “哼撤嫩!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蠢终,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤序攘,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后寻拂,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體两踏,經(jīng)...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年兜喻,在試婚紗的時候發(fā)現(xiàn)自己被綠了梦染。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡朴皆,死狀恐怖帕识,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情遂铡,我是刑警寧澤肮疗,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站扒接,受9級特大地震影響伪货,放射性物質(zhì)發(fā)生泄漏们衙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一碱呼、第九天 我趴在偏房一處隱蔽的房頂上張望蒙挑。 院中可真熱鬧,春花似錦愚臀、人聲如沸忆蚀。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽馋袜。三九已至,卻和暖如春舶斧,著一層夾襖步出監(jiān)牢的瞬間欣鳖,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工茴厉, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留泽台,地道東北人。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓呀忧,卻偏偏與公主長得像师痕,于是被迫代替她去往敵國和親溃睹。 傳聞我的和親對象是個殘疾皇子而账,可洞房花燭夜當晚...
    茶點故事閱讀 45,077評論 2 355

推薦閱讀更多精彩內(nèi)容