保存SecureString

时间:2008-09-29 06:38:36

标签: .net securestring

我正在处理的程序的一个功能请求是能够保存用户输入的凭据列表,以便可以共享它们。启发此请求的具体用例是在大型企业网络上使用我们的程序,该网络由相当好的LAN组成,由一个片状WAN连接。我们的想法是,不是让我们的程序在WAN关闭时击败广域网,而是发送一个包含严密保护的管理员凭据的“配置”文件,在每个局域网中运行并压缩结果并通过电子邮件发送给它回来。

呀。

我最初的本能是嘲笑这个请求 - 保存密码? 真的吗?当然,公司的网络部门更愿意尝试销售他们拥有的任何广域网产品 - 但事实证明,我使用凭据的其中一个类可以采用SecureString,并且,好吧,寻找可以为人们节省一些努力的方法总是很好的。这让我想知道:

是否可以保存加密的SecureString,以便将敏感数据保存到文件中并在其他地方打开?

你有什么想法,Stack Overflow?

7 个答案:

答案 0 :(得分:5)

SecureString中没有保存支持,它旨在作为保护内存中托管字符串的机制,仅用于与非托管API进行交互。如果密码存储在System.String实例中,则由于System.String的性质,安全性会降低。垃圾收集和实习的存在会使密码在内存中的保留时间超过必要的时间。同样由于.NET的大量调试工具,通过反射或其他.NET API访问字符串会更加容易,即使没有更长的生命周期。

如果您要在磁盘上保存密码,那么您的安全性就会受到很大影响。如果有人可以物理访问机器或管理员级远程访问,那么您可以做的最好的事情就是让它变得更加困难,但绝不可能。使用加密API,将其存储在安全位置,配置访问权限。

除此之外,Merus,我建议你尝试改进整个系统,因为对于像你所描述的用例(假设我理解它),你最好存储哈希而不是实际密码。

答案 1 :(得分:4)

您可能希望查看比较密码哈希 你会有一个由用户名和可能的其他常量组成的盐,后跟字符串。然后,您可以将其传递给哈希算法,例如SHA1 * 例如,

using System.Security.Cryptography;

public byte[] GetPasswordHash(string username, string password, string salt)
{
    // get salted byte[] buffer, containing username, password and some (constant) salt
    byte[] buffer;
    using (MemoryStream stream = new MemoryStream())
    using (StreamWriter writer = new StreamWriter(stream))
    {
        writer.Write(salt);
        writer.Write(username);
        writer.Write(password);
        writer.Flush();

        buffer = stream.ToArray();
    }

    // create a hash
    SHA1 sha1 = SHA1.Create();
    return sha1.ComputeHash(buffer);
}

然后,您会将GetPasswordHash(username, expectedPassword, salt)的结果与GetPasswordHash(username, givenPassword, salt)进行比较 如果您使用用户名和密码实现自己的用户列表,则可能只考虑保存哈希值(GetPasswordHash(username, givenPassword, salt))并与保存的哈希值进行比较。

答案 2 :(得分:3)

如果您的意思是保存SecureString的加密字节,那么这将不起作用 - SecureString的密钥与用户和进程相关联。在不同的进程或不同的用户中读取这些字节,并且无法解密字符串。

答案 3 :(得分:3)

这会破坏SecureString的要点,SecureString保证驻留在内存中。因此,如果您将其保存到文件中,您可以将其保存为普通字符串,因为它不再是“安全的”。

答案 4 :(得分:1)

您可能需要查看IsolatedStorageFileStream class。它指定了编写和存储文件数据的方法,只能由程序集访问。

我认为你不能在它上面使用SecureString。

答案 5 :(得分:1)

SecureString不可序列化,因此您不能仅使用一些提供的序列化程序(二进制文件,XML等)保存它。

你也不能只访问例如来自securestring对象的“Password”属性,因为没有这样的东西。 你必须使用编组和一点管道才能做到这一点。 如果你想在某个地方存储用户凭据,我建议你自己加密它们,因为这样可以减少以后的开发。在评估了SecureString方法之后,我们决定自己实现一些东西,但这些只是我的2美分。

答案 6 :(得分:0)

如上所述,SecureString不是在这种情况下使用的最佳方式。

如果我需要分享用户凭据,我可能会分享用户名哈希+盐渍密码,所以你会是安全的,只分享代码的密码,而不是它的内容。

这方面的简单方法是使用 BCryt库where there's a .NET representation of it),只需将用户名和密码表示形式托管在准备共享的表中

这就是你如何使用它:

StringBuilder sb = new StringBuilder();

// run ADO.NET / Entity Framework / etc and query your DB with something like:
"SELECT user_id, username, password FROM [TblUsers];"

// loop through the results

sb.AppendFormat(
       "INSERT INTO [TblSharedUsers] SELECT '{0}','{1}','{2}'",            
           dr["id"], dr["username"],
           BCrypt.HashPassword(dr["password"], BCrypt.GenerateSalt(12));
       );

// then run sb.ToSTring() agains your db

在客户端,您可以创建一个新的AuthenticationProvider(因此,当使用IoCDI的网络不可用时,可以轻松更改) {1}}并检查用户密码,如

TblSharedUsers

我希望这可以帮助有同样问题的人。