這可能是目前最安全的數據加密傳輸解決方案


問題

為了安全性起見,客戶要求客戶端必須將數據加密后才能傳給服務端。

起先,准備使用非對稱加密(RSA)方式,但是發現它對原始文本長度有限制。

而對稱加密(AES)沒有長度限制,但是使用固定密鑰存在暴露的風險。

有沒有兩全其美的辦法呢?

思路

密鑰肯定每個用戶不同,而要驗證用戶則必須登錄。

因此,唯一可以安全獲取密鑰的時機,只能是在登錄時。

而為了保證用戶名密碼傳輸安全,可以使用RSA公鑰加密后傳輸,所有客戶端使用同一公鑰也沒問題。

登錄成功后,服務端將生成token和AES密鑰返回給客戶端。但是,返回的AES密鑰是經過加密的,而加密密鑰則是“用戶名+密碼”。

這樣保證了,只有剛才成功登錄的客戶端才能解密出AES密鑰。

以后的傳輸,全部使用AES加密,服務端可以根據token從緩存獲取AES密鑰解密。

整體流程如下圖:

 

 

服務端實現

下面是示例服務端的實現代碼:

[HttpPost("Login")]
public LoginOutput Login(LoginInput input)
{
    var userName = RsaHelper.Decrypt(input.UserName, privateKey);
    var password = RsaHelper.Decrypt(input.Password, privateKey);
    (byte[] tmpKey, byte[] tmpIV) = AesHelper.CreateKeyIV(userName + password, password + userName);

    var token = Guid.NewGuid().ToString("N"); 
    (byte[] key, byte[] iv) = AesHelper.CreateKeyIV();
    _cache.Add(token, (key, iv));
    return new LoginOutput
    {
        Token = token,
        Key = AesHelper.Encrypt(Convert.ToBase64String(key), tmpKey, tmpIV),
        IV = AesHelper.Encrypt(Convert.ToBase64String(iv), tmpKey, tmpIV)
    };
}

[HttpPost("TestMethod")]
public string TestMethod([FromQuery]string token, [FromBody]string cipherText)
{
    (byte[] key, byte[] iv) = _cache[token];
    return AesHelper.Decrypt(cipherText, key, iv);
}

Login用於驗證用戶密碼並返回token和AES密鑰.

TestMethod用於演示接收客戶端數據如何解密,為了演示方便,直接在URL傳遞token。

客戶端實現

使用xunit測試項目演示客戶端操作,代碼如下:

[Fact]
public async void Test1()
{
    //登錄獲得AES密鑰
    var response = await _httpClient.PostAsync( "/Demo/Login",
        JsonContent.Create(new WebApplication1.LoginInput{ 
            UserName = RsaHelper.Encrypt(userName, publicKey),
            Password = RsaHelper.Encrypt(password, publicKey)
        }));
    var loginResult = await response.Content.ReadFromJsonAsync<WebApplication1.LoginOutput>();

    (byte[] tmpKey, byte[] tmpIV) = AesHelper.CreateKeyIV(userName + password, password + userName);

    byte[] key =Convert.FromBase64String(AesHelper.Decrypt(loginResult.Key, tmpKey, tmpIV));
    byte[] iv = Convert.FromBase64String(AesHelper.Decrypt(loginResult.IV, tmpKey, tmpIV));

    //使用AES密鑰加密
    var cipherText = AesHelper.Encrypt(PlainText, key, iv);
    _output.WriteLine(cipherText);
    response = await _httpClient.PostAsync("/Demo/TestMethod?token=" + loginResult.Token,
        JsonContent.Create(cipherText));

    var decryptResult = await response.Content.ReadAsStringAsync();

    _output.WriteLine(decryptResult);
    Assert.Equal(PlainText, decryptResult);
}

 

將大量數據(千字文)加密后傳給服務。

可以看到,返回了正確的原始數

結論

通過同時使用RSA+AES,保證了密鑰和數據的安全性。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM