关于c#:在发送到数据库之前在字符串中存储密码

Storing a password in a string before sending to database

我想学习一些处理密码的好方法。我将从我的项目中提供一些代码片段,并解释我担心和好奇的事情。

让我们从获取用户输入的代码开始,我的按钮事件代码:

1
2
string username = txtUser.Text;
string password = Hash.EncryptString(txtPass.Text);

在这里,我的想法是,将密码以明文形式存储在字符串中可能是不好的做法?我知道这可能不是解决这个问题的方法(特别是因为我将它以明文发送给另一个方法,然后将它存储在一个字符串中),但这里我调用了一个我创建的方法来将密码转换为哈希。"hash"类中的encryptString方法:

1
2
3
4
5
6
7
8
9
10
11
12
   public static string EncryptString(string text) {
        var sha1 = System.Security.Cryptography.SHA1.Create();
        var inputBytes = Encoding.ASCII.GetBytes(text);
        text =""; //clear string
        var hash = sha1.ComputeHash(inputBytes);

        var sb = new StringBuilder();
        for (var i = 0; i < hash.Length; i++)
            sb.Append(hash[i].ToString("X2"));

        return sb.ToString();
    }

这里没什么好说的,我用sha1加密对密码进行了散列。我认为在我使用后清除字符串是明智的,这样密码就不会再被存储了?

稍后在验证或添加用户的代码中,我将获取或创建一个惟一的salt,并将其与哈希密码混合,然后再次使用encryptString方法,然后再进入数据库。

以隐私和安全的名义,这是一个好的做法吗?或者更确切地说,目前我的代码中存在哪些漏洞,如何修复它们?


这里有两个问题:

  • 你知道的那个——堆中未保护的内存,以及
  • 你不知道的那个——你不应该散列密码和Sha1一起。
  • 让我们来解决这两个问题:

    (1)许多安全人员会推荐SecureString来保护您的堆内存。然而,事实证明,SecureString并没有广告中的那么好。如果你想知道原因,你可以在YouTube上观看这个SecureString设计评论。它很长,但是很好,你只需要看10到15分钟就可以看到问题所在。

    在Web应用程序的特定上下文中,您可以尝试各种特技,以防止明文密码在内存中,但在一天结束时,您将对象作为一个字符串从请求对象中获取。您无法控制该请求对象的垃圾收集。在你把手放在上面之后,试图保护你的记忆,就像把创可贴放在筛子上一样。

    底线:别担心。您无法解决框架固有的问题。

    (2)您对密码存储的想法正落在前10位开发者密码错误中的第4位。

    特洛伊亨特有一篇优秀的文章,介绍了访问数据库的人如何破解密码,以及如何使用bcrypt或pbkdf2(bcrypt更好)来防止此类攻击。


    你想防范什么情况?您在这里面临的主要威胁是包含字符串密码的内存转储,或其他内存分析调试工具。现在,这可能是一个合法的威胁,也可能不是,取决于更多的上下文。但是,如果txtPass.Text是客户端控件,那么坦率地说,在内存工具开始使用时,您更容易受到密钥记录器在每个应用程序输入时简单获取输入的风险。

    注意:

    1
    text =""; //clear string

    不从非托管堆中移除字符串。它只是将名为text的变量中的引用更改为间隔的零长度字符串,也称为string.Empty。实际字符串仍然存在于托管堆上,并且可能仍然存在于与txtPass下的输入机制相关的各种非托管位置。