如何在不暴露明文的情况下通过网络传输SecureString(或类似字符串)?

时间:2019-04-09 12:03:39

标签: c# .net security https securestring

我有一个带有“秘密”(例如密码)的应用程序

我不想将此秘密本地存储在用户可访问的上下文文件中,因此我计划通过HTTPS从服务器按需检索它。

出于明显的原因,我也不希望它在内存中可见(例如,从崩溃日志中可见),因此我将机密存储在SecureString中

但是,当我序列化SecureString时,结果仅显示明文字符串的长度,例如{"Length":4}

但是,如果我以明文形式传输密码,那么即使随后将其存储在SecureString中,该密码也将在内存中检索到的JSON中可见

是否有任何方法可以序列化SecureString或接收JSON并将纯文本字符串转换为SecureString而不需要存储在内存中的中间常规字符串?

在这种情况下,我必须存储/发送实际密码,而不是例如一次使用的一次性密钥:这超出了我的控制范围。我需要实际的纯文本密码才能访问其他服务,因此通常的“先哈希然后比较哈希”也不适用

1 个答案:

答案 0 :(得分:0)

这是一个使用RSA加密将字符串发送给您拥有公钥的人的有效示例。在您的问题中,您希望服务器向客户端发送消息(密码),并让客户端安全地使用该密码,而不必担心中间的日志记录等。为此,您需要让客户端创建私钥文件并将公钥文件发送到服务器,然后服务器可以安全地进行通信。

可能有一些库使这种方式更容易。

[Test]
public void TestEncryption()
{
    /////////////// Create Key Files ////////////////
    RSACryptoServiceProvider provider = new RSACryptoServiceProvider(4096);

    //Create the key files on disk and distribute them to sender / reciever
    var publicKey =  provider.ToXmlString(false);
    var privateKey =  provider.ToXmlString(true);

    /////////////// Actual Test ////////////////

    //send with the public key
    byte[] sent = Send("hey",publicKey);

    //cannot receive with public key
    var ex = Assert.Throws<CryptographicException>(()=>Receive(sent, publicKey));
    StringAssert.Contains("Key does not exist",ex.Message);

    //but can with private key
    Assert.AreEqual("hey", Receive(sent,privateKey));
}

private Byte[] Send(string send, string publicKey)
{
    using (RSACryptoServiceProvider rsaSender = new RSACryptoServiceProvider())
    {
        rsaSender.FromXmlString(publicKey);
        return rsaSender.Encrypt(Encoding.ASCII.GetBytes(send), false);
    }
}

private object Receive(byte[] sent, string privateKey)
{
    using (RSACryptoServiceProvider rsaReceiver = new RSACryptoServiceProvider())
    {
        rsaReceiver.FromXmlString(privateKey);
        return Encoding.ASCII.GetString(rsaReceiver.Decrypt(sent, false));
    }
}