在发送到数据库之前将密码存储在字符串中

时间:2017-04-30 20:18:02

标签: c# security passwords password-protection password-encryption

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

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

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

我的想法是,将密码以明文形式存储在字符串中可能是不好的做法?我知道这可能不是解决方案(特别是因为我将它以明文形式发送到另一个方法然后将其存储在字符串中),但是在这里我调用了一个我创建的方法来制作密码成哈希。 “哈希”类中的EncryptString方法:

   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方法,然后再进入数据库。

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

2 个答案:

答案 0 :(得分:1)

您尝试防范的情况如何?您受到威胁的主要方案是包含字符串密码或其他内存分析调试工具的内存转储。现在,可能是合法威胁,也可能不是,取决于 lot 更多上下文。但是,如果txtPass.Text是客户端控件,那么坦率地说,当内存工具发挥作用时,你更有可能只是为每个应用程序抓取输入的键盘记录器< / em>正在输入。

请注意:

text = ""; //clear string

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

答案 1 :(得分:1)

这里有两个问题:

  1. 你知道的那个 - 堆中没有保护的内存,
  2. 你不知道的那个 - 你不应该是哈希密码 使用SHA1。
  3. 让我们解决两个问题:

    (1)许多安全人员会建议SecureString来保护您的堆内存。然而,事实证明SecureString并不如宣传的那么好。如果您想了解原因,可以在youtube上观看此SecureString design review。它很长,但它非常好,你真的只需要观看10或15分钟就可以看到它的问题。

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

    底线:不要担心。你无法解决这个框架所固有的问题。

    (2)您对密码存储的想法属于Top 10 Developer Crypto Mistakes中的#4。

    Troy Hunt有一篇很好的文章,展示了如何通过访问数据库来破解密码,以及如何使用bcrypt或pbkdf2防止此类攻击(bcrypt更好)。