zoukankan      html  css  js  c++  java
  • 这可能是目前最安全的数据加密传输解决方案

    问题

    为了安全性起见,客户要求客户端必须将数据加密后才能传给服务端。

    起先,准备使用非对称加密(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,保证了密钥和数据的安全性。

  • 相关阅读:
    微服务实战(二):使用API Gateway
    微服务实战(一):微服务架构的优势与不足
    在WIN7、WIN10操作系统用WebDAV映射网络驱动器需要的操作
    docker开机启动和docker-compose开机启动执行相应的各个docker容器
    /etc/rc.d/init.d自启动程序说明
    C# 通过反射实现对象映射:将2个属性相近的对象相互转换
    添加windows右键菜单:使用exe应用程序打开文件/文件夹
    .NET5 MVC Program.cs 笔记
    前端 JS 正则表达式积累
    VS Code 快捷键
  • 原文地址:https://www.cnblogs.com/dongh/p/15464721.html
Copyright © 2011-2022 走看看