程序員看“孫楊抗檢”本質:如何解決接口通信雙方身份信任問題?

今天接手了一個Spring Boot的後端項目,裡面主要是一些給移動端用的接口,整個項目的框架、包括前後端的交互格式之類的東西都已經由老大定義好了,我直接進行開發就行。

不像以前普通的網頁端接口,前端直接把數據傳到後端,後端業務處理完畢後再把數據返回,這次這個項目的所有接口都是經過加密處理的,好像既有AES對稱加密算法、又有RSA非對稱加密算法在裡面,反正早上一開始老大給我講項目架構的時候我是沒聽太懂。

到了中午吃飯的時候,我趁機纏著老大給我講解了一下他接口加密的設計思想。

程序員看“孫楊抗檢”本質:如何解決接口通信雙方身份信任問題?

接口為什麼要加密?

我問老大:“我們APP需要先登錄才能使用,後端接口也有做鑑權,接口加密不是多此一舉嗎?

老大搖了搖頭說,APP調用的接口都是暴露在外的,別人一抓包就能拿到接口地址,再直接請求接口地址就能繞過我們的APP拿到數據,登錄、鑑權只是最基本的措施,接口加密之後,這樣就算別人抓包,看到的請求參數和返回數據都是加密後的密文,我們項目中使用AES對稱加密算法來加密數據。

我似懂非懂的點點頭,見我點頭,老大反過來問我:“那你說說使用RSA非對稱加密算法的目的是什麼?

我只得擺出一副黑人問號臉……

老大白了我一眼說,使用RSA算法目的一是拿公鑰加密AES的密鑰,二是拿私鑰對數據進行簽名,可以起到防篡改、防抵賴的作用。

防篡改?防抵賴?聽完我繼續黑人問號臉……

老大說給你舉個例子就明白了,孫楊知道吧?最近挺火那個,新聞上說他抗拒藥檢的原因是對藥檢人員的資質存在疑問,說白了就是他不相信藥檢工作人員的身份,那麼這個雙方的身份信任問題,其實就跟我們前後端接口通信需要首先確認對方身份一樣,可以通過RSA算法來解決。

  1. 首先我們為世界反興奮劑機構官方生成一對RSA密鑰對,私鑰由機構秘密持有,公鑰將公佈給孫楊在內的所有運動員,然後機構官方使用私鑰為藥檢工作人員的資質證書進行簽名(相當於蓋上官方機構的章)
  2. 當藥檢工作人員需要對孫楊進行藥檢時,首先出示已經簽名過的資質證書,此時孫楊可以拿機構官方公佈的公鑰對簽名進行校驗,如果簽名校驗通過則可以證明資質證書確實是由官方簽發的,藥檢人員身份沒有問題;如果簽名校驗失敗則證明資質證書是偽造的,藥檢人員身份存在問題

我正要繼續再問點什麼,老大看著碗裡的飯吞了吞口水對我說:“我飯都涼了,要不你先自己看看代碼?”

我:……

好在經過我一下午努力,總算弄明白了整個接口加密通信的流程,下面我們一起來了解一下吧。

AES對稱加密算法示意圖

首先簡單介紹一下AES對稱加密,我畫了一張AES加密算法的草圖(大家湊合看吧):

程序員看“孫楊抗檢”本質:如何解決接口通信雙方身份信任問題?

發送方使用密鑰將明文進行AES加密,將密文和密鑰傳給接收方,接收方使用同樣的密鑰對密文進行AES解密,得到明文。

RSA非對稱加密算法示意圖

接著我再簡單介紹一下RSA非對稱加密,我又畫了一張RSA加密算法的草圖:

程序員看“孫楊抗檢”本質:如何解決接口通信雙方身份信任問題?

首先接收方生成一對RSA密鑰(公鑰、私鑰),公鑰公開給發送方,私鑰自己保留;發送方使用公鑰將明文加密得到密文,將密文發送給接收方,接收方使用私鑰將密文解密得到明文。同樣的,接收方也可以使用私鑰對數據進行簽名後回傳給發送方,發送方可以使用公鑰來驗證簽名,從而判斷數據是否來自接收方。

AES+RSA配合實現接口加密,完整流程圖

首先看一下從客戶端請求開始,到服務端解密的一整套流程:

程序員看“孫楊抗檢”本質:如何解決接口通信雙方身份信任問題?

看起來還不錯吧?下面我們一起來看看怎麼實現的吧。正式開始前,首先介紹一下前期的準備工作:

  • 服務端生成RSA密鑰對(公鑰、私鑰),公鑰下發給所有客戶端、私鑰自己持有
  • 客戶端生成RSA密鑰對(公鑰、私鑰),公鑰提交到服務端保存、私鑰自己持有

客戶端發送請求加密流程

首先介紹一下客戶端發送一次請求完整的流程:

程序員看“孫楊抗檢”本質:如何解決接口通信雙方身份信任問題?

  1. 隨機生成一個固定長度的用於AES加密的密鑰
  2. 使用服務端的RSA公鑰對AES密鑰明文進行加密生成AES密鑰密文
  3. 使用AES密鑰明文對參數明文進行AES加密生成參數密文
  4. 生成請求時間戳
  5. 生成固定長度的隨機字符串
  6. 將參數密文、AES密鑰密文、時間戳、隨機字符串進行MD5計算,得到md5值
  7. 使用RSA私鑰對md5值簽名,得到簽名值
  8. 最後將參數密文、AES密鑰密文、時間戳、隨機字符串、簽名值一起發送到服務端

服務端解密流程:

再來看一下服務端接收到數據後的揭秘流程:

程序員看“孫楊抗檢”本質:如何解決接口通信雙方身份信任問題?

  1. 比較請求時間戳與當前時間戳差值是否在系統設置的超時時間內,超過則認為請求過期
  2. 從緩存查找隨機字符串是否已存在,如果已存在則認為是一次重複請求,不存在則將該隨機字符串放入緩存
  3. 將參數密文、AES密鑰密文、時間戳、隨機字符串進行MD5計算,得到md5值
  4. 使用客戶端RSA公鑰驗證簽名是否來自合法授權的客戶端,防止非法客戶端篡改數據
  5. 使用自己的RSA私鑰解密AES密鑰密文,得到AES密鑰明文
  6. 使用ES密鑰明文解密參數密文得到參數明文
  7. 使用aesKey解密encryptParams得到明文參數
  8. 進行正常的業務處理流程
  9. 返回數據加密流程與客戶端一致,直接使用客戶端的AES密鑰即可。

彩蛋

有眼尖的小夥伴有可能已經發現了,上面的例子中還夾雜了一些時間戳、隨機字符串概念在裡面,這些參數都有什麼用呢?這些懸念就留到下一篇裡揭曉吧。下一篇將會是實戰篇,我會基於Spring Boot項目,通過自定義註解的方式來實現接口的自動加解密。


我是一名正兒八經的程序員,喜歡我的文章歡迎 轉發 及 關注,我也會經常與大家分享工作當中的代碼那些事兒。


分享到:


相關文章: