揭密支付安全:為什么你的交易無(wú)法被篡改

0 評(píng)論 2529 瀏覽 18 收藏 13 分鐘

隨著數(shù)字支付的普及,支付安全成為了我們不可忽視的重要議題。本文將深入探討支付系統(tǒng)中的一個(gè)關(guān)鍵安全主題——防篡改與防抵賴,揭示為何支付平臺(tái)必須實(shí)施簽名驗(yàn)簽機(jī)制,以及如何確保交易的安全性和真實(shí)性。

今天主要講清楚支付系統(tǒng)中常見的安全主題之一:防篡改與防抵賴。包括為什么支付平臺(tái)所有對(duì)外服務(wù)接口要做簽名驗(yàn)簽,哪些是安全的算法,哪些是不安全的算法,以及對(duì)應(yīng)的核心代碼實(shí)現(xiàn)。

通過(guò)這篇文章,你可以了解到:

  1. 什么是簽名驗(yàn)簽
  2. 支付系統(tǒng)為什么一定要做簽名驗(yàn)簽
  3. 哪些是安全的算法,哪些是不安全的算法
  4. 常見簽名驗(yàn)簽算法核心代碼
  5. 聯(lián)調(diào)中常見的問(wèn)題

一、什么是數(shù)字簽名驗(yàn)簽

在電子支付的萬(wàn)億級(jí)市場(chǎng)中,安全無(wú)疑是核心中的核心。安全是一個(gè)很龐大的領(lǐng)域,“簽名與驗(yàn)簽”是安全領(lǐng)域里面一個(gè)重要的分支。那什么是簽名驗(yàn)簽?zāi)兀?/p>

簽名驗(yàn)簽是數(shù)字加密領(lǐng)域的兩個(gè)基本概念。

  1. 簽名:發(fā)送者將數(shù)據(jù)通過(guò)特定算法和密鑰轉(zhuǎn)換成一串唯一的密文串,也稱之為數(shù)字簽名,和報(bào)文信息一起發(fā)給接收方。
  2. 驗(yàn)簽:接收者根據(jù)接收的數(shù)據(jù)、數(shù)字簽名進(jìn)行驗(yàn)證,確認(rèn)數(shù)據(jù)的完整性,以證明數(shù)據(jù)未被篡改,且確實(shí)來(lái)自聲稱的發(fā)送方。如果驗(yàn)簽成功,就可以確信數(shù)據(jù)是完好且合法的。

假設(shè)被簽名的數(shù)據(jù)(m),簽名串(Σ),散列函數(shù)(H),私鑰(Pr),公鑰(Pu),加密算法(S),解密算法(S^),判斷相等(eq)。

簡(jiǎn)化后的數(shù)學(xué)公式如下:

簽名:Σ=S[H(m), Pr]。

驗(yàn)簽:f(v)=[H(m) eq S^(Σ, Pu)]。

流程如下:

簽名流程:

  1. 散列消息:對(duì)消息(m)應(yīng)用散列函數(shù)(H)生成散列值(h)。
  2. 加密散列值:使用發(fā)送方的私鑰 ( Pr ) 對(duì)散列值 ( h ) 進(jìn)行加密,生成簽名 ( Σ )。Σ = S(h, Pr)

把數(shù)字簽名(Σ)和原始消息(m)一起發(fā)給接收方。

驗(yàn)簽流程:

  1. 散列收到的消息:使用同樣的散列函數(shù) ( H ) 對(duì)消息 ( m ) 生成散列值 ( h’ ),也就是:h’ = H(m)。
  2. 解密簽名:使用發(fā)送方的公鑰 ( Pu ) 對(duì)簽名 (Σ ) 進(jìn)行解密,得到散列值 ( h ),也就是:h = S^(Σ, Pu)。
  3. 比較散列值:比較解密得到的散列值 ( h ) 與直接對(duì)消息 ( m ) 散列得到的 ( h’ ) 是否一致。驗(yàn)證成功條件:h = h’ 。

如果兩個(gè)散列值相等,那么驗(yàn)簽成功,消息(m)被認(rèn)為是完整沒(méi)有被篡改,且確實(shí)來(lái)自聲稱的發(fā)送方。如果不一致,就是驗(yàn)簽失敗,消息可能被篡改,或者簽名是偽造的。

現(xiàn)實(shí)中的算法會(huì)復(fù)雜非常多,比如RSA,ECDSA等,還涉及到填充方案,隨機(jī)數(shù)生成,數(shù)據(jù)編碼等。

二、支付系統(tǒng)為什么一定要做簽名驗(yàn)簽

銀行怎么判斷扣款請(qǐng)求是從確定的支付平臺(tái)發(fā)出來(lái)的,且數(shù)據(jù)沒(méi)有被篡改?商戶不承認(rèn)發(fā)送過(guò)某筆交易怎么辦?簽名驗(yàn)簽技術(shù)專門解密類似的問(wèn)題。

簽名驗(yàn)簽主要解決3個(gè)問(wèn)題:

1)身份驗(yàn)證:確認(rèn)支付信息是由真正的發(fā)送方發(fā)出,防止冒名頂替。

如果無(wú)法做身份驗(yàn)證,支付寶就無(wú)法知道針對(duì)你的賬戶扣款99塊的請(qǐng)求是真實(shí)由你樓下小賣部發(fā)出去的,還是我冒充去扣的款。

2)完整性校驗(yàn):確認(rèn)支付信息在傳輸過(guò)程中未被篡改,每一筆交易都是完整、準(zhǔn)確的。

如果無(wú)法校驗(yàn)完整性,那么我在公共場(chǎng)景安裝一個(gè)免費(fèi)WIFI,然后截獲你的微信轉(zhuǎn)賬請(qǐng)求,把接收者修改成我的賬號(hào),再轉(zhuǎn)發(fā)給微信,微信就有可能會(huì)把錢轉(zhuǎn)到我的賬號(hào)里。

3)防抵賴性:避免任何一方否認(rèn)曾經(jīng)進(jìn)行過(guò)的交易,提供法律證據(jù)支持。

比如微信支付調(diào)用銀行扣款100塊,銀行返回成功,商戶也給用戶發(fā)貨了,幾天后銀行說(shuō)這筆扣款成功的消息不是他們返回的,他們沒(méi)有扣款。而簽名驗(yàn)簽就能讓銀行無(wú)法抵賴。

流程:

  1. 雙方先交換密鑰,可以通過(guò)線下郵件交換,也可以通過(guò)線上自助平臺(tái)交換。
  2. 請(qǐng)求方發(fā)出交易報(bào)文前使用自己的私鑰進(jìn)行簽名,接收方接收?qǐng)?bào)文后先進(jìn)行驗(yàn)簽,驗(yàn)簽通過(guò)后再進(jìn)行業(yè)務(wù)處理。
  3. 接收方處理完業(yè)務(wù),返回前使用自己的私鑰進(jìn)行簽名,請(qǐng)求方接收返回報(bào)文后先進(jìn)行驗(yàn)簽,驗(yàn)簽通過(guò)后再進(jìn)行業(yè)務(wù)處理。

三、安全簽名驗(yàn)簽算法推薦

安全一直是一個(gè)相對(duì)的概念,很多曾經(jīng)是安全的算法,隨著計(jì)算機(jī)技術(shù)的發(fā)展,已經(jīng)不安全了,以后到了量子計(jì)算的時(shí)代,現(xiàn)在大部分的算法都將不再安全。

一般而言,安全同時(shí)取決于算法和密鑰長(zhǎng)度。比如SHA-256就比MD5更安全,RSA-2048就比RSA-1024更安全。

已經(jīng)被認(rèn)為不安全的算法有MD5、SHA-1等算法,容易受到碰撞攻擊,不應(yīng)該在支付系統(tǒng)中使用。

仍然被認(rèn)為是安全的算法有:SHA-256,SHA-3, RSA-1024,RSA-2048,ECDSA等。

當(dāng)前最常見推薦的算法是RSA-2048。RSA-1024以前使用得多,但因?yàn)槊荑€長(zhǎng)度較短,也已經(jīng)不再推薦使用。

SHA-256和MD5一樣,只是一種單純的散列算法,其實(shí)是不適合做簽名驗(yàn)簽算法的,因?yàn)樾枰p方共用相同取值的密鑰,一旦泄露,無(wú)法確認(rèn)是被哪方泄露,也就是只解決了完整性校驗(yàn),無(wú)法解決身份驗(yàn)證和防抵賴性。但因?yàn)槭褂煤?jiǎn)單,國(guó)內(nèi)外仍然有不少的支付公司在大量使用。

四、常見簽名驗(yàn)簽算法核心代碼

下面以RSA(SHA256withRSA)為例,示例代碼如下:

import java.security.KeyFactory;

import java.security.PrivateKey;

import java.security.PublicKey;

import java.security.Signature;

import java.security.spec.PKCS8EncodedKeySpec;

import java.security.spec.X509EncodedKeySpec;

public class RSASignatureUtil {

   

   // 使用私鑰對(duì)數(shù)據(jù)進(jìn)行簽名

   public static byte[] sign(byte[] data, byte[] privateKey) throws Exception {

       PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKey);

       KeyFactory keyFactory = KeyFactory.getInstance("RSA");

       PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);

       Signature signature = Signature.getInstance("SHA256withRSA");

       signature.initSign(priKey);

       signature.update(data);

       return signature.sign();

   }

   // 使用公鑰驗(yàn)證簽名

   public static boolean verify(byte[] data, byte[] publicKey, byte[] signatureBytes) throws Exception {

       X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey);

       KeyFactory keyFactory = KeyFactory.getInstance("RSA");

       PublicKey pubKey = keyFactory.generatePublic(keySpec);

       Signature signature = Signature.getInstance("SHA256withRSA");

       signature.initVerify(pubKey);

       signature.update(data);

       return signature.verify(signatureBytes);

   }

}

簽名輸出是字節(jié)碼,還需要編碼,一般使用base64。

如果使用SHA-256(很多公司仍在使用,但不推薦),如下:

import java.security.MessageDigest;

public class SHA256Util {

   // 使用SHA-256對(duì)數(shù)據(jù)進(jìn)行散列

   public static byte[] hash(byte[] data) throws Exception {

       MessageDigest digest = MessageDigest.getInstance("SHA-256");

       return digest.digest(data);

   }

}

這里data已經(jīng)是加了API密鑰(也稱為API KEY)。所謂的API密鑰,就是交易雙方共享的一個(gè)密鑰,這樣雙方生成的哈希值才會(huì)一致。

五、聯(lián)調(diào)中常見的問(wèn)題

不管是與商戶的聯(lián)調(diào),還是與支付渠道(或銀行)之間的聯(lián)調(diào),簽名驗(yàn)簽都是非常耗費(fèi)精力的環(huán)節(jié)。驗(yàn)簽不通過(guò)通常有以下幾個(gè)情況:

  1. 密鑰不匹配:雙方以為自己都配置了正確的密鑰,但實(shí)際沒(méi)有。
  2. 數(shù)據(jù)編碼不一致:比如一方使用GBK,一方使用UTF-8。
  3. 原始數(shù)據(jù)選擇不一致:比如接口文檔要求拼接10個(gè)字段,但是代碼實(shí)現(xiàn)卻只拼接了9個(gè)字段?;蛘咭环?jīng)]有把空值放入計(jì)算,另一方把空值也放入計(jì)算。
  4. 原始數(shù)據(jù)排序方式不一致:比如接口要求按key的升序排列,調(diào)用方卻忘記排序就進(jìn)行簽名。
  5. 字符轉(zhuǎn)義不一致:特殊字段的轉(zhuǎn)義必須保持一致。

解決上述問(wèn)題的最好辦法,就是讓服務(wù)提供方提供一段示例代碼,以及示例報(bào)文+示例簽名,然后在本地使用main方法先跑成功,再移植到項(xiàng)目代碼中。

六、結(jié)束語(yǔ)

主要講了支付安全領(lǐng)域內(nèi)的簽名驗(yàn)簽名相關(guān)內(nèi)容,包括重要性,原理,常見算法及核心JAVA代碼實(shí)現(xiàn)。

但是還有一個(gè)同樣非常重要的問(wèn)題沒(méi)有講:如何安全儲(chǔ)存密鑰?如果密鑰放在代碼里或數(shù)據(jù)庫(kù)里,開發(fā)人員是可以直接獲得的,如果不小心泄露出去怎么辦?

應(yīng)對(duì)的解決方案就是創(chuàng)建一個(gè)密鑰中心專門負(fù)責(zé)密鑰的管理,無(wú)論加密解密還是簽名驗(yàn)簽,全部調(diào)用密鑰中心來(lái)處理,業(yè)務(wù)系統(tǒng)不接觸密鑰明文。

那又來(lái)了一個(gè)新的問(wèn)題:這個(gè)密鑰中心如何設(shè)計(jì)和實(shí)現(xiàn),才能既保證很高的安全性,又能有非常高的性能表現(xiàn)呢?后面有時(shí)間再單獨(dú)聊聊。

本文由人人都是產(chǎn)品經(jīng)理作者【隱墨星辰】,微信公眾號(hào):【隱墨星辰】,原創(chuàng)/授權(quán) 發(fā)布于人人都是產(chǎn)品經(jīng)理,未經(jīng)許可,禁止轉(zhuǎn)載。

題圖來(lái)自Unsplash,基于 CC0 協(xié)議。

更多精彩內(nèi)容,請(qǐng)關(guān)注人人都是產(chǎn)品經(jīng)理微信公眾號(hào)或下載App
評(píng)論
評(píng)論請(qǐng)登錄
  1. 目前還沒(méi)評(píng)論,等你發(fā)揮!