最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

淺析非對稱加密在接口參數(shù)中的實現(xiàn)

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

背景

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

對稱加密,比較有代表性的就是 AES,密鑰只有一個,客戶端和服務端都要進行存儲,但是對客戶端來說,比較容易泄露,需要定期進行更換。

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

非對稱加密 + 對稱加密,這個應該是用的比較多的一種,做了一個折中處理,用 RSA 的公鑰加密 AES 的密鑰,然后用 AES 去加密請求數(shù)據(jù)。

下面老黃就用幾個簡單的例子來演示一下非對稱加密這一塊。

非對稱加密

這里介紹的是純純的非對稱加密,還不是結合對稱加密的。

這種情況,如果真的使用,一般是會在登錄接口,再細一點的話,就是密碼那個字段的加密。

先來看看簡單的流程圖

后端接口處理

后端 API 接口需要提供兩個接口

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

獲取公鑰

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

    // 模擬從數(shù)據(jù)庫或緩存中取數(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ù)接受,不過有一些網(wǎng)站的登陸接口是直接傳密文
    // 所以這里也演示一下這種方式
    var data = await new StreamReader(Request.Body).ReadToEndAsync();
    if (string.IsNullOrWhiteSpace(data)) return BadRequest("invalid param");

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

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

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

前端頁面處理

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

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

<!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>

運行效果大致如下:

這個例子不算復雜,應該比較好理解。

下面再來看看非對稱加密 + 對稱解密的方式。

非對稱加密 + 對稱加密

這兩種加密結合的,網(wǎng)上其實很多例子,不過每個實現(xiàn)都會有一些細微的差別。

這種相對來說,適用的場景就比較多了,基本都可以覆蓋。

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

后端接口處理

后端 API 接口也是需要提供兩個接口,公鑰獲取和上面的是一樣的,變動的是解密這一塊,因為這里還引入了 AES 。

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

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

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

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

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

前端頁面處理

前端這一塊其實變動也不會大,主要是多了一步 AES 密鑰的生成和 AES 的加密。

$(function () {
    getPublicKeyFromServer();

    $("#btnSubmit").click(function () {
        var encrypt = new JSEncrypt();
        encrypt.setPublicKey(localStorage.getItem("spk"));
        
        // 隨機生成 aes 的密鑰
        var aesKey = getAesKey();
        // 用公鑰去加密這個密鑰
        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)出來了。

一些考慮

可能有朋友會問,前端生成的 AES 密鑰可信嗎?

畢竟有流傳類似這樣一句話 任何客戶端傳過來的數(shù)據(jù)都是不能直接信任的。

有這種顧慮也算正常。

這個時候就需要考慮服務端生成密鑰的方案了:

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

首先考慮密鑰也是密文傳輸?shù)模苑斩撕涂蛻舳艘瑫r擁有一對公鑰和私鑰。

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

這種的話,交互邏輯會復雜一些。

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

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

相關文章

  • Java 通過 二三法 巧解前端數(shù)據(jù)顯示

    Java 通過 二三法 巧解前端數(shù)據(jù)顯示

    實踐來源于理論,做開發(fā)前肯定要先了解相關的規(guī)則和原理,看到標題或許你會好奇什么是二三法。本篇文章帶你深入了解,需要的朋友可以參考下
    2021-10-10
  • SpringBoot 中html的頁面間跳轉問題小結

    SpringBoot 中html的頁面間跳轉問題小結

    這篇文章主要介紹了SpringBoot 中html的頁面間跳轉問題小結,本文給大家分享兩種方法,結合實例代碼給大家介紹的非常詳細,需要的朋友可以參考下
    2023-10-10
  • java實現(xiàn)圖片裁切的工具類實例

    java實現(xiàn)圖片裁切的工具類實例

    這篇文章主要介紹了java實現(xiàn)圖片裁切的工具類實例,涉及Java針對圖片的讀取、修改等相關操作技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-11-11
  • Java雇員管理小項目

    Java雇員管理小項目

    這篇文章主要為大家詳細介紹了Java雇員管理小項目,理解面向對象編程,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • java中將list用逗號隔開拼成字符串的4種方法例子

    java中將list用逗號隔開拼成字符串的4種方法例子

    我們經(jīng)常在開發(fā)過程之中會遇到需要把返回的Id list轉換為一個使用逗號(,)分隔的字符串,下面這篇文章主要給大家介紹了關于java中將list用逗號隔開拼成字符串的4種方法例子,需要的朋友可以參考下
    2024-01-01
  • SpringBoot利用Junit動態(tài)代理實現(xiàn)Mock方法

    SpringBoot利用Junit動態(tài)代理實現(xiàn)Mock方法

    說到Spring Boot 單元測試主要有兩個主流集成分別是Mockito,Junit,這個各有特點,在實際開發(fā)中,我想要的測試框架應該是這個框架集成者,本文給大家介紹了SpringBoot利用Junit動態(tài)代理實現(xiàn)Mock方法,需要的朋友可以參考下
    2024-04-04
  • Spring中@RestController和@Controller的使用及區(qū)別

    Spring中@RestController和@Controller的使用及區(qū)別

    這篇文章主要介紹了Spring中@RestController和@Controller的使用及區(qū)別,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-03-03
  • Spring MVC請求參數(shù)接收的全面總結教程

    Spring MVC請求參數(shù)接收的全面總結教程

    這篇文章主要給大家總結介紹了關于Spring MVC請求參數(shù)接收的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2018-08-08
  • Java Scala之模式匹配與隱式轉換

    Java Scala之模式匹配與隱式轉換

    在Java中我們有switch case default這三個組成的基礎語法,在Scala中我們是有match和case組成 default的作用由case代替,本文詳細介紹了Scala的模式匹配與隱式轉換,感興趣的可以參考本文
    2023-04-04
  • IDEA創(chuàng)建Servlet程序的兩種實現(xiàn)方法

    IDEA創(chuàng)建Servlet程序的兩種實現(xiàn)方法

    Servlet是JavaWeb應用程序中不可或缺的組件之一,本文主要介紹了IDEA創(chuàng)建Servlet程序的兩種實現(xiàn)方法,具有一定的參考價值,感興趣的可以了解一下
    2023-10-10

最新評論

阜城县| 馆陶县| 弥渡县| 葫芦岛市| 武穴市| 卢龙县| 贵南县| 呼图壁县| 仪陇县| 泸定县| 拜城县| 玉溪市| 丁青县| 白水县| 年辖:市辖区| 庄河市| 永年县| 青神县| 定陶县| 阜新市| 宣武区| 伊宁市| 马山县| 曲水县| 阳西县| 安义县| 虎林市| 崇信县| 德昌县| 额济纳旗| 扎赉特旗| 彰化县| 徐闻县| 泰和县| 伊宁县| 东辽县| 巧家县| 集贤县| 石首市| 巴里| 抚宁县|