欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

淺析非對(duì)稱(chēng)加密在接口參數(shù)中的實(shí)現(xiàn)

 更新時(shí)間:2023年02月17日 09:26:16   作者:catcherwong  
接口層做數(shù)據(jù)加密應(yīng)該算是老生常談的一件事了,業(yè)界用的比較多的,不外乎是對(duì)稱(chēng)加密,非對(duì)稱(chēng)加密以及兩者的結(jié)合。本文就來(lái)聊聊非對(duì)稱(chēng)加密在接口參數(shù)中的實(shí)現(xiàn),希望對(duì)大家有所幫助

背景

接口層做數(shù)據(jù)加密應(yīng)該算是老生常談的一件事了,業(yè)界用的比較多的,不外乎是對(duì)稱(chēng)加密,非對(duì)稱(chēng)加密以及兩者的結(jié)合。

對(duì)稱(chēng)加密,比較有代表性的就是 AES,密鑰只有一個(gè),客戶(hù)端和服務(wù)端都要進(jìn)行存儲(chǔ),但是對(duì)客戶(hù)端來(lái)說(shuō),比較容易泄露,需要定期進(jìn)行更換。

非對(duì)稱(chēng)加密,比較有代表性的就是 RSA,有公鑰和私鑰,正常是服務(wù)端生成,將私鑰保留在服務(wù)端,公鑰派發(fā)出去,然后是客戶(hù)端用公鑰進(jìn)行加密,服務(wù)端用私鑰進(jìn)行解密。相對(duì)于對(duì)稱(chēng)加密來(lái)說(shuō),是安全了一些,但是加解密的速度會(huì)慢一些,如果要加密的內(nèi)容還比較多,還要進(jìn)行分段處理,比較麻煩。

非對(duì)稱(chēng)加密 + 對(duì)稱(chēng)加密,這個(gè)應(yīng)該是用的比較多的一種,做了一個(gè)折中處理,用 RSA 的公鑰加密 AES 的密鑰,然后用 AES 去加密請(qǐng)求數(shù)據(jù)。

下面老黃就用幾個(gè)簡(jiǎn)單的例子來(lái)演示一下非對(duì)稱(chēng)加密這一塊。

非對(duì)稱(chēng)加密

這里介紹的是純純的非對(duì)稱(chēng)加密,還不是結(jié)合對(duì)稱(chēng)加密的。

這種情況,如果真的使用,一般是會(huì)在登錄接口,再細(xì)一點(diǎn)的話(huà),就是密碼那個(gè)字段的加密。

先來(lái)看看簡(jiǎn)單的流程圖

后端接口處理

后端 API 接口需要提供兩個(gè)接口

  • 根據(jù)應(yīng)用客戶(hù)端獲取公鑰(當(dāng)然把公鑰寫(xiě)死在客戶(hù)端代碼里也是可以的)
  • 解密處理數(shù)據(jù)

獲取公鑰

[HttpGet("req-pub")]
public IActionResult ReqPub([FromQuery] string appId)
{
    if(string.IsNullOrWhiteSpace(appId)) return BadRequest("invalid param");

    // 模擬從數(shù)據(jù)庫(kù)或緩存中取數(shù)據(jù)
    var publicKey = RSAKeyMapping.GetServerPublicKeyByAppId(appId);
    if(string.IsNullOrWhiteSpace(publicKey)) return BadRequest("invalid appId");

    return Ok(new { data = publicKey });
}

解密處理

[HttpPost]
public async Task<IActionResult> Post([FromHeader] string appId)
{
    if (string.IsNullOrWhiteSpace(appId)) return BadRequest("invalid appId");

    // 這里本可以用參數(shù)接受,不過(guò)有一些網(wǎng)站的登陸接口是直接傳密文
    // 所以這里也演示一下這種方式
    var data = await new StreamReader(Request.Body).ReadToEndAsync();
    if (string.IsNullOrWhiteSpace(data)) return BadRequest("invalid param");

    // 模擬從數(shù)據(jù)庫(kù)或緩存中取數(shù)據(jù)
    var rsaKey = RSAKeyMapping.GetByAppId(appId);
    if (rsaKey == null) return BadRequest("invalid appId");

    // 解密,正常解密后會(huì)是一個(gè) JSON 字符串,然后反序列化即可
    var decData = EncryptProvider.RSADecrypt(
        rsaKey.ServerPrivateKey, 
        Convert.FromBase64String(data), 
        RSAEncryptionPadding.Pkcs1, 
        true);

    return Ok($"Hello, {System.Text.Encoding.UTF8.GetString(decData)}");
}

前端頁(yè)面處理

前端用最原生的 HTML + JavaScript 來(lái)演示,這里需要用到 jsencryptcrypto-js。

大致流程的話(huà),打開(kāi)頁(yè)面就從服務(wù)端獲取到公鑰,點(diǎn)擊按鈕,就會(huì)把文本框中的內(nèi)容用公鑰去加密,然后調(diào)用服務(wù)端的解密接口。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>RSA sample</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.3/jquery.min.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/jsencrypt/3.3.1/jsencrypt.min.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
    <script>
        let appId = "appId-2";
        let url = "http://localhost:7775";
        $(function () {
            // 獲取公鑰
            getPublicKeyFromServer();

            $("#btnSubmit").click(function () {
                var encrypt = new JSEncrypt();
                encrypt.setPublicKey(localStorage.getItem("spk"));
                var encData = encrypt.encrypt($("#txtData").val());
                sendBizReq(encData)
            });
        });
        
        function getPublicKeyFromServer() {
            $.get(url + "/com/req-pub?appId=" + appId, function (data, status) {
                localStorage.setItem("spk", data.data)
            });
        }
        
        function sendBizReq(data) {
            $.ajax({
                url: url + "/biz",
                type: 'post',
                // dataType: 'json',
                data: data,
                headers: {
                    'appId': appId,
                    'Content-Type': 'application/json'
                },
                success: function (res) {
                    console.log(res)
                    alert(res);
                },
                error: function (e) {
                    console.log(e)
                }
            });
        }
    </script>
</head>
<body>
    <div>
        <input type="text" id="txtData" />
        <button id="btnSubmit">submit</button>
    </div>
</body>
</html>

運(yùn)行效果大致如下:

這個(gè)例子不算復(fù)雜,應(yīng)該比較好理解。

下面再來(lái)看看非對(duì)稱(chēng)加密 + 對(duì)稱(chēng)解密的方式。

非對(duì)稱(chēng)加密 + 對(duì)稱(chēng)加密

這兩種加密結(jié)合的,網(wǎng)上其實(shí)很多例子,不過(guò)每個(gè)實(shí)現(xiàn)都會(huì)有一些細(xì)微的差別。

這種相對(duì)來(lái)說(shuō),適用的場(chǎng)景就比較多了,基本都可以覆蓋。

同樣看看簡(jiǎn)單的流程圖,再看如何實(shí)現(xiàn)。

后端接口處理

后端 API 接口也是需要提供兩個(gè)接口,公鑰獲取和上面的是一樣的,變動(dòng)的是解密這一塊,因?yàn)檫@里還引入了 AES 。

[HttpPost]
public IActionResult Post([FromHeader] string appId, [FromBody] RequestDto dto)
{
    if(string.IsNullOrWhiteSpace(appId)) return BadRequest("invalid appId");
    // 這里正常用實(shí)體接收,不從流讀取了
    if (dto == null 
        || string.IsNullOrWhiteSpace(dto.EP)
        || string.IsNullOrWhiteSpace(dto.EAK)) return BadRequest("invalid param");

    // 模擬從數(shù)據(jù)庫(kù)或緩存中取數(shù)據(jù)
    var rsaKey = RSAKeyMapping.GetByAppId(appId);
    if (rsaKey == null) return BadRequest("invalid appId");

    // 解密客戶(hù)端傳過(guò)來(lái)的 AES 密鑰
    var decAesKey = EncryptProvider.RSADecrypt(
        rsaKey.PrivateKey, 
        Convert.FromBase64String(dto.EAK),
        RSAEncryptionPadding.Pkcs1, 
        true);

    // 根據(jù)解密的密鑰,進(jìn)行 AES 解密
    var decData = EncryptProvider.AESDecrypt(
        dto.EP, 
        System.Text.Encoding.UTF8.GetString(decAesKey));

    return Ok($"Hello, {decData}");
}

前端頁(yè)面處理

前端這一塊其實(shí)變動(dòng)也不會(huì)大,主要是多了一步 AES 密鑰的生成和 AES 的加密。

$(function () {
    getPublicKeyFromServer();

    $("#btnSubmit").click(function () {
        var encrypt = new JSEncrypt();
        encrypt.setPublicKey(localStorage.getItem("spk"));
        
        // 隨機(jī)生成 aes 的密鑰
        var aesKey = getAesKey();
        // 用公鑰去加密這個(gè)密鑰
        var encAesKey = encrypt.encrypt(aesKey);
        // 用 aes 的密鑰去加密數(shù)據(jù)
        var encData = aesEncrypt($("#txtData").val(), aesKey);
        sendBizReq(encData, encAesKey)
    });
});

function sendBizReq(data, aesKey) {
    $.ajax({
        url: url + "/biz",
        type: 'post',
        // dataType: 'json',
        data: JSON.stringify({ ep: data, eak: aesKey }),
        headers: {
            'appId': appId,
            'Content-Type': 'application/json'
        },
        success: function (res) {
            console.log(res)
            alert(res);
        },
        error: function (e) {
            console.log(e)
        }
    });
}

function getAesKey() {
    var s = [];
    var hexDigits = "0123456789abcdef";
    for (var i = 0; i < 32; i++) {
        s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
    }
    s[14] = "4";
    s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1);
    s[8] = s[13] = s[18] = s[23];
    var uuid = s.join("");
    return uuid;
}

function aesEncrypt(data, key) {
    var encryptedData = CryptoJS.AES.encrypt(
        CryptoJS.enc.Utf8.parse(data), 
        CryptoJS.enc.Utf8.parse(key), 
        {
            mode: CryptoJS.mode.ECB,
            padding: CryptoJS.pad.Pkcs7
        });

    return encryptedData.toString();
}

效果已經(jīng)出來(lái)了。

一些考慮

可能有朋友會(huì)問(wèn),前端生成的 AES 密鑰可信嗎?

畢竟有流傳類(lèi)似這樣一句話(huà) 任何客戶(hù)端傳過(guò)來(lái)的數(shù)據(jù)都是不能直接信任的

有這種顧慮也算正常。

這個(gè)時(shí)候就需要考慮服務(wù)端生成密鑰的方案了:

生成其實(shí)是一件小事,傳輸是一件比較核心的事。

首先考慮密鑰也是密文傳輸?shù)模苑?wù)端和客戶(hù)端要同時(shí)擁有一對(duì)公鑰和私鑰。

服務(wù)端在向客戶(hù)端傳輸密鑰時(shí),要用客戶(hù)端的公鑰進(jìn)行加密,然后客戶(hù)端用自己私鑰進(jìn)行解密獲得,這樣才能保證密鑰的“安全性”。

這種的話(huà),交互邏輯會(huì)復(fù)雜一些。

除了 RSA 算法,后面可能還要嘗試一下國(guó)密算法中的 SM2。

到此這篇關(guān)于淺析非對(duì)稱(chēng)加密在接口參數(shù)中的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)非對(duì)稱(chēng)加密在接口參數(shù)中實(shí)現(xiàn)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Zookeeper ZkClient使用介紹

    Zookeeper ZkClient使用介紹

    ZkClient是Github上?個(gè)開(kāi)源的zookeeper客戶(hù)端,在Zookeeper原生API接口之上進(jìn)行了包裝,是?個(gè)更易用的Zookeeper客戶(hù)端,同時(shí),zkClient在內(nèi)部還實(shí)現(xiàn)了諸如Session超時(shí)重連、Watcher反復(fù)注冊(cè)等功能
    2022-09-09
  • java字符串遍歷的幾種常用方法總結(jié)

    java字符串遍歷的幾種常用方法總結(jié)

    Java字符串是一系列的Unicode字符序列,但是它卻常常被誤認(rèn)為是char序列,這篇文章主要給大家介紹了關(guān)于java字符串遍歷的幾種常用方法,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-04-04
  • spring中的BeanFactory與FactoryBean的講解

    spring中的BeanFactory與FactoryBean的講解

    今天小編就為大家分享一篇關(guān)于spring中的BeanFactory與FactoryBean的講解,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2019-01-01
  • java實(shí)現(xiàn)的海盜算法優(yōu)化版

    java實(shí)現(xiàn)的海盜算法優(yōu)化版

    這篇文章主要介紹了java實(shí)現(xiàn)的海盜算法優(yōu)化版,結(jié)合實(shí)例形式分析了java海盜算法的具體實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2017-07-07
  • java ArrayList按照同一屬性進(jìn)行分組

    java ArrayList按照同一屬性進(jìn)行分組

    這篇文章主要介紹了java ArrayList按照同一屬性進(jìn)行分組的相關(guān)資料,需要的朋友可以參考下
    2017-02-02
  • spring聲明式事務(wù)@Transactional開(kāi)發(fā)常犯的幾個(gè)錯(cuò)誤及最新解決方案

    spring聲明式事務(wù)@Transactional開(kāi)發(fā)常犯的幾個(gè)錯(cuò)誤及最新解決方案

    使用聲明式事務(wù)@Transactional進(jìn)行事務(wù)一致性的管理,在開(kāi)發(fā)過(guò)程中,發(fā)現(xiàn)很多開(kāi)發(fā)同學(xué)都用錯(cuò)了spring聲明式事務(wù)@Transactional或使用不規(guī)范,導(dǎo)致出現(xiàn)各種事務(wù)問(wèn)題,這篇文章主要介紹了spring聲明式事務(wù)@Transactional開(kāi)發(fā)常犯的幾個(gè)錯(cuò)誤及解決辦法,需要的朋友可以參考下
    2024-02-02
  • 單臺(tái)Spring Cloud Eureka升級(jí)到三臺(tái)Eureka高可用集群

    單臺(tái)Spring Cloud Eureka升級(jí)到三臺(tái)Eureka高可用集群

    今天小編就為大家分享一篇關(guān)于單臺(tái)Spring Cloud Eureka升級(jí)到三臺(tái)Eureka高可用集群,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2018-12-12
  • Java 詳細(xì)講解線(xiàn)程安全與同步附實(shí)例與注釋

    Java 詳細(xì)講解線(xiàn)程安全與同步附實(shí)例與注釋

    線(xiàn)程安全是多線(xiàn)程編程時(shí)的計(jì)算機(jī)程序代碼中的一個(gè)概念。在擁有共享數(shù)據(jù)的多條線(xiàn)程并行執(zhí)行的程序中,線(xiàn)程安全的代碼會(huì)通過(guò)同步機(jī)制保證各個(gè)線(xiàn)程都可以正常且正確的執(zhí)行,不會(huì)出現(xiàn)數(shù)據(jù)污染等意外情況
    2022-04-04
  • Arthas在線(xiàn)java進(jìn)程診斷工具在線(xiàn)調(diào)試神器詳解

    Arthas在線(xiàn)java進(jìn)程診斷工具在線(xiàn)調(diào)試神器詳解

    Arthas是 Alibaba 開(kāi)源的Java診斷工具,深受開(kāi)發(fā)者喜愛(ài)。這篇文章主要介紹了Arthas在線(xiàn)java進(jìn)程診斷工具 在線(xiàn)調(diào)試神器,需要的朋友可以參考下
    2021-11-11
  • spring boot mybatis多數(shù)據(jù)源解決方案過(guò)程解析

    spring boot mybatis多數(shù)據(jù)源解決方案過(guò)程解析

    這篇文章主要介紹了spring boot mybatis多數(shù)據(jù)源解決方案過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-11-11

最新評(píng)論