【问题标题】:Storing a password in a string before sending to database在发送到数据库之前将密码存储在字符串中
【发布时间】:2017-04-30 20:18:01
【问题描述】:

我正在尝试学习一些处理密码的好习惯。我将从我的项目中提供一些代码 sn-ps 并解释我担心和好奇的事情。

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

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

我的想法是,将密码以明文形式存储在字符串中可能是不好的做法?我知道这可能不是解决方案(特别是因为我以明文形式将其发送到另一个方法,然后将其存储在字符串中),但在这里我调用了我创建的方法将密码转换为哈希。 “Hash”类中的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 加密对密码进行哈希处理。我认为在使用后清除字符串以便不再存储密码会很聪明?

稍后在我验证或添加用户的代码中,我将获取或创建一个唯一的盐并将其与散列密码混合并再次使用 EncryptString 方法,然后再提交到数据库。

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

【问题讨论】:

  • 次要注意:这是一个错误命名的方法 - 它的 named 就像它正在做 wrong 的事情(加密密码),而实际上它正在做某种正确的事情(散列密码)。当然,Salt 会有很长的路要走,而且有很多 sha1 解密表等可用。
  • 除了@MarcGravell 的评论,您确实应该使用 pbkdf2、bcrypt、scrypt 或 argon2 来散列密码。在这四个中,我个人推荐的是 bcrypt。

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


【解决方案1】:

这里有两个问题:

  1. 您所知道的——堆中未受保护的内存,以及
  2. 你不知道的那个——你不应该散列密码 使用 SHA1。

让我们同时解决这两个问题:

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

在 Web 应用程序的特定上下文中,您可以尝试各种技巧来防止明文密码在内存中,但最终您会从 Request Object 中以字符串形式获取对象。您无法控制该请求对象的垃圾收集。在你拿到记忆后试图保护它就像把创可贴放在筛子上一样。

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

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

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

【讨论】:

  • 感谢您的出色回复和非常好的学习资源。 :)
【解决方案2】:

您要防范什么情况?您在这里面临的主要威胁是包含字符串密码的内存转储或其他内存分析调试工具。现在,这可能是合法的威胁,也可能不是,这取决于很多更多的上下文。但是,如果txtPass.Text 是客户端控件,那么坦率地说,当记忆工具开始发挥作用时,您就更有可能被键盘记录器简单地抓取每个应用程序的输入已输入。

注意:

text = ""; //clear string

从非托管堆中删除字符串。它只是将名为 text 的变量中的 reference 更改为内部零长度字符串,也就是 string.Emptyactual 字符串仍然存在于托管堆中,并且可能仍然存在于与输入机制相关的各种非托管位置underneath txtPass

【讨论】:

  • 感谢您的快速回复和消除一些误解。嗯,这只是一个学校项目,应该是一个用于交通教育的网络应用程序。所以安全部分根本不是那么重要,我只是想在此过程中学习一些额外的东西。
猜你喜欢
  • 2011-04-28
  • 2021-03-18
  • 1970-01-01
  • 2016-03-05
  • 1970-01-01
  • 2014-12-25
  • 2017-01-22
  • 2021-10-05
  • 1970-01-01
相关资源
最近更新 更多