當前位置: 妍妍網 > 碼農

優雅的處理 API 介面敏感數據加解密(方案詳解)

2024-06-21碼農

架構師(JiaGouX)

我們都是架構師!
架構未來,你來不來?

  • 一、背景與目標

  • 二、方案設計

  • 對稱加密、非對稱加密、哈希演算法、驗簽演算法

  • HTTPS原理概述

  • 微信支付加解密原理

  • 介面加解密設計思路

  • 三、技術實作

  • 四、常見問題

  • 五、安全性分析

  • 一、背景與目標

    隨著網路技術的快速發展,數據安全問題日益突出。為了防止爬蟲、防請求篡改、防請求重放,以及驗證數據完整性,本方案結合HTTPS原理和微信支付加解密設計,透過對稱加密、非對稱加密、簽名等技術,為API介面提供加解密設計和落地。

    二、方案設計

    對稱加密、非對稱加密、哈希演算法、驗簽演算法

  • 對稱加密: 采用相同的金鑰進行加密和解密。具有加密速度快、計算量小的優點,但金鑰的安全傳輸是問題。在本方案中,對稱加密主要用於數據的實際加密傳輸。

  • 非對稱加密: 使用一對金鑰(公鑰和私鑰)進行加密和解密。公鑰用於加密數據,私鑰用於解密數據。非對稱加密可以確保金鑰的安全傳輸,但加密速度較慢,不適合長文本加密。在本方案中,非對稱加密主要用於對稱金鑰的加密。

  • 哈希演算法: 無論使用者輸入什麽長度的原始數據,經過計算後輸出的密文都是固定長度的,只要原數據稍有改變,輸出的「摘要」便完全不同

  • 簽名演算法: 一般指的是,透過私鑰對數據進行簽名,然後透過公鑰對數據進行驗簽

  • HTTPS原理概述

    HTTPS( Hypertext Transfer Protocol Secure )是一種透過電腦網路進行安全通訊的傳輸協定。它利用SSL/TLS協定在HTTP套用層進行通訊加密,透過證書進行身份驗證,從而確保數據傳輸的安全性和完整性。

    微信支付加解密原理

  • 請求簽名: 透過商戶API證書私鑰,對每一次請求進行RSA-SHA256簽名,微信支付進行驗簽

  • 回呼驗簽: 微信支付透過平台證書私鑰,對每一次回呼進行RSA-SHA256簽名,商戶接收到請求後,透過平台正式公鑰進行驗簽

  • 回呼解密: 商戶根據配置的apiV3金鑰,對加密數據進行AES-256-GCM解密

  • 介面加解密設計思路

  • 金鑰交換: 客戶端使用伺服端的公鑰對對稱加密的金鑰進行加密,然後將密文金鑰發送給伺服端。伺服端使用自己的私鑰解密得到對稱加密的明文金鑰。

  • 數據加密: 客戶端使用對稱加密的明文金鑰對介面數據進行加密,然後發送給伺服端。伺服端使用相同的對稱加密金鑰對數據進行解密。

  • 數據哈希(簽名): 在數據發送前,客戶端計算數據的哈希值,並將哈希值作為數據的一部份發送給伺服端。伺服端收到數據後,使用相同的演算法計算哈希值,並與客戶端發送的哈希值進行比較,以驗證數據的完整性。

  • 數據有效性校驗: 在數據發送前,客戶端將當前時間作為數據的一部份發送給伺服端。伺服端收到數據後,解密得到參數中的時間,並與伺服端當前時間進行比較,以驗證請求是否過期,防止請求重放。

  • 三、技術實作

    1、金鑰生成與管理:

    透過工具生成非對稱金鑰對,伺服端負責保管私鑰。(客戶端也可以定期從伺服端獲取公鑰(傳輸過程中有泄露的風險),並保存到LocalStorage。)

    2、加密演算法選擇:

    對稱加密演算法可選用常用的AES,非對稱加密演算法可選用常用的RSA。哈希演算法可選用SHA-256、MD5,簽名演算法可選用RSA-SHA256等。根據Hutool加密演算法如下:

    // 對稱金鑰
    String key = "key";
    AES aes = SecureUtil.aes(key.getBytes());
    // 加密
    String ciphertext = aes.encryptBase64(content);
    // 解密
    String result = aes.decryptStr(ciphertext);
    // 非對稱公鑰
    String publicKey = "xxxxxxx";
    // 對稱金鑰
    String key = "key";
    RSA rsa = new RSA(null, publicKey);
    // 對對稱金鑰進行加密
    String ciphertextKey = rsa.encryptBase64(key, KeyType.PublicKey);

    // 非對稱私鑰
    String privateKey = "xxxxxxx";
    RSA rsa2 = new RSA(privateKey, null);
    // 對加密的對稱金鑰進行解密
    String key = rsa2.encryptBase64(ciphertextKey, KeyType.PrivateKey);
    String data = "測試";
    Digester sha256 = new Digester(DigestAlgorithm.SHA256);
    System.out.println(sha256.digestHex(data));
    // 暫不考慮
    String publicKey = "xxxxx";
    String privateKey = "xxxxx";
    String data = "測試";
    Sign privateSign = SecureUtil.sign(SignAlgorithm.SHA256withRSA, privateKey, null);
    String sign = new String(Base64.getEncoder().encode(privateSign.sign(data)));
    System.out.println("簽名:" + sign);
    Sign publicSign = SecureUtil.sign(SignAlgorithm.SHA256withRSA, null, publicKey);
    System.out.println(publicSign.verify(data.getBytes(), Base64.getDecoder().decode(sign.getBytes())));



    3、簽名規則:

    等queryString和body參數加密後,將queryString、時間戳、明文對稱金鑰、body參數按順序進行拼接,然後透過SHA256演算法進行哈希得到簽名sign,然後將sign放在header中進行傳遞

    4、參數傳遞:
  • ek(encryt-key): xxxxxxx(非對稱加密後的對稱金鑰)

  • ts: xxxxxxx(時間戳)

  • sign: xxxxxxx

  • 將請求參數 queryString 拼成" param1=value1&param2=value2 "格式

    queryString 進行對稱加密,得到" ciphertext=xxxxx ",並重新拼接到url後面

    query參數可以參考GET請求

    body參數可以透過對稱加密得到base64密文,直接用body進行傳輸

    例如:

    url?ciphertext=xxxxx
    body:xxxxxxxx

    5、後端處理:
    1. 請求有效驗證: 獲取header中ts參數,得到時間戳並判斷時間戳是否超過一定時間;

    2. 解密對稱金鑰: 透過私鑰解密header中的ek參數,得到明文的對稱金鑰key;

    3. 驗簽: 將queryString、時間戳、明文對稱金鑰、body參數按順序進行拼接,然後透過SHA256演算法進行哈希得到簽名sign,與header中的sign做比較;

    4. 解密參數: 透過明文對稱金鑰,分別解密queryString、body參數;

    5. 加密響應結果: 請求完成後,將響應結果透過對稱加密得到base64密文,並返回給客戶端

    四、常見問題

    Q:為什麽需要參考HTTPS來設計介面加解密?

    A:HTTPS結合了對稱加密和非對稱加密,安全性更高,同時也能滿足效率要求

    Q:如果只使用對稱加密有什麽問題?

    A:客戶端是不安全的,很容易暴露金鑰,只要一旦暴露,加密就形同虛設

    Q:如果只使用非對稱加密有什麽問題?

    A:

  • 非對稱加密不支持超長文本加密(RSA只支持117字節);

  • 非對稱加密效率太慢

  • Q:介面參數已經加密了,是否還有必要簽名?

    A:有必要,生產環境不是每一個介面都需要加密的。但是每一個介面都需要防篡改、防重放

    Q:簽名演算法為什麽沒有采用RSA-SHA256?

    A:

  • RSA-SHA256簽名演算法只能私鑰簽名,公鑰驗簽。

  • 客戶端存的是公鑰,如果要采用該演算法,需要再定義一套非對稱金鑰,加重了維護成本。

  • 現在采用哈希演算法SHA256進行模擬簽名,其中混入了明文的對稱金鑰,也可以防止模擬簽名

  • Q:用了對稱和非對稱混合加密,非對稱公鑰保存在客戶端,還是有可能泄露,怎麽保證安全?

    A:

  • 前端程式碼壓縮、混淆;

  • 公鑰不要直接寫到程式碼裏,分段、加密保存;

  • 即使公鑰暴露了,對稱金鑰每次都是新生成的,抓包也拿不到本次請求的對稱金鑰,也就沒有辦法對結果解密

  • Q:對稱和非對稱同時使用的話,怎麽保證加解密的效率?

    A:請求參數和響應結果實際還是透過對稱加密,非對稱只會對對稱金鑰進行加解密,所以效率和對稱加密差不多4

    Q:該方案是否是絕對安全?如果不是,是否有絕對安全的加解密方案?

    A:

  • 不是,如果客戶端被破解了,使用者可以模擬客戶端發起請求

  • 暫時沒有,客戶端對於互聯網都是透明的,只要客戶端被破解了,都可以模擬客戶端發起請求

  • 五、安全性分析

    本方案結合對稱加密和非對稱加密的優點,既保證了數據傳輸的安全性,又提高了加密解密的效率。但是需要考慮客戶端公鑰的安全性。

    防篡改: 請求參數都進行了簽名,只要客戶端公鑰不泄露,無法修改請求參數;

    防爬蟲: 請求參數進行了簽名和加密,無法模擬客戶端請求;響應結果進行了加密,即使抓包拿到了結果,也無法進行解密

    防重放: 請求頭中引入時間戳,並且時間戳也進行了驗簽,可以防止篡改,每次伺服端接收到請求都會驗證時間戳的有效性。(短時間內的重放暫時阻止不了,可以考慮在後端在緩存進行驗證,但目前業務用不上)

    如喜歡本文,請點選右上角,把文章分享到朋友圈
    如有想了解學習的技術點,請留言給若飛安排分享

    因公眾號更改推播規則,請點「在看」並加「星標」 第一時間獲取精彩技術分享

    ·END·

    相關閱讀:

    作者:Jason22

    來源:https://juejin.cn/post/7358368402795692082

    版權申明:內容來源網路,僅供學習研究,版權歸原創者所有。如有侵權煩請告知,我們會立即刪除並表示歉意。謝謝!

    架構師

    我們都是架構師!

    關註 架構師(JiaGouX),添加「星標」

    獲取每天技術幹貨,一起成為牛逼架構師

    技術群請 加若飛: 1321113940 進架構師群

    投稿、合作、版權等信箱: [email protected]