【问题标题】:Best practices for encrypting and decrypting passwords? (C#/.NET)加密和解密密码的最佳实践? (C#/.NET)
【发布时间】:2010-10-21 13:33:09
【问题描述】:

我需要在(最好是文本)文件中存储和加密密码,以后我需要能够解密。密码用于我使用的另一项服务,需要以明文形式(通过 SSL)发送到那里。这不是我能改变的。该领域的最佳实践是什么?如何对恶意用户的密码进行一定程度的保护?

我的平台是带有 C#/.NET 3.5 的 WinForms。

谢谢。

【问题讨论】:

  • 应该重新命名为“加密密码的最佳实践”,因为解密密码绝对不是最佳实践。
  • 不,不应该;那将是一个完全不同的问题。
  • 解密密码的最佳做法是:不要这样做。

标签: c# encryption


【解决方案1】:

我假设您想加密密码,因为它将在用户计算机上并且他们将(可能)能够找到并使用它?如果是这样,您基本上就搞砸了-无论您做什么,因为它在用户域中,他们将能够获取它并找出加密并获取加密密码(请记住,使用 Reflector - 以及它的克隆 - 是'不是大多数人无法触及的)并解密它,他们拥有它。简而言之,您所做的只是混淆密码,而不是保护密码。

我建议实际上将其移出用户控制。例如,建立一个与客户端通信并在请求时安全地返回密码的 Web 服务。这还允许您在将来需要时更改密码,并为您提供验证合法用户的方法。

【讨论】:

  • +1,但是我们应该如何保护对密码返回网络服务的访问?
  • @Matthew 任何标准的服务认证系统都可以很好地工作。
  • @Robert:您愿意详细说明一下吗?如果用户他/她自己可以调用该服务,那么安全点就没有实际意义。我没有得到什么?谢谢。
  • @Eyvind 例如为所有用户提供一个密钥(用户名/密码,唯一的 ID),并要求在调用时获取密码,例如: public string GetPassword(string username,字符串密码)客户端将他们的密钥放入他们的应用程序中并对其进行身份验证,因此您知道您可以“信任”他们。这还允许您在将来需要时阻止用户。 WCF/Web 服务身份验证有很多内容:stackoverflow.com/search?q=web+service+wcf+authentication
  • 与其将密码返回给客户端,然后使用它直接连接到第三方服务,不如考虑运行一个经过身份验证的 Web 服务,将所有客户端请求代理到真实服务;您的第三方服务密码永远不会发送给客户。这对您来说更昂贵,并且会增加一些调用开销,但会提供最佳安全性。取决于保护密码的价值。
【解决方案2】:

为什么需要解密密码?通常存储和比较密码的加盐哈希。如果您加密/解密密码,您将再次以纯文本形式获得密码,这很危险。如果某些用户具有相同的密码,则应对哈希进行加盐以避免重复的哈希。对于盐,您可以使用用户名。

HashAlgorithm hash = new SHA256Managed();
string password = "12345";
string salt = "UserName";

// compute hash of the password prefixing password with the salt
byte[] plainTextBytes = Encoding.UTF8.GetBytes(salt + password);
byte[] hashBytes = hash.ComputeHash(plainTextBytes);

string hashValue = Convert.ToBase64String(hashBytes);

您可以计算密码的加盐哈希并将其存储在您的文件中。在身份验证期间,您再次计算用户条目的哈希并将此哈希与存储的密码哈希进行比较。 由于从哈希中获取纯文本应该非常困难(它永远不可能,总是时间问题),因此密码受到保护,不会再次作为纯文本读取。

提示:切勿存储或发送未加密的密码。如果得到新密码,请尽快加密!

【讨论】:

  • 如问题所述,我必须解密它,因为该服务只接受未加密形式的密码。
  • 如果无法避免,我会使用 AES,但请注意,任何加密密钥都可以从程序集中读取,因此并不能真正保存。
  • 您好,SHA256 加密是否足以让程序将密码存储在纯文本文件中?我正在为我的密码存储程序寻找描述方法,但我不确定应该使用哪个。
  • 很难说这是否足够,因为我不知道您的应用程序。这仅取决于使用 pw 保护的数据有多重要,以及您可以通过哪些通道访问 pw。基本上,密钥越长越安全。在您的情况下,我假设您只是试图阻止普通用户在只有视图人员可以访问它的环境中读取纯密码(否则 sou 不会将其存储在密码中)。对于这种情况,这就足够了。
【解决方案3】:

System.Security 程序集中的System.Security.Cryptography.ProtectedData 使用一些 Windows API 使用只有它知道的密码来加密数据。

一个可能的用途是拥有一个实际执行需要密码的操作的 Windows 服务。用户与通过远程处理或 WCF 调用服务进行交互的应用程序。只要服务使用 DataProtectionScope.CurrentUser 并且服务用户与登录用户不同,密码应该是非常安全的。

这当然假设用户作为受限用户运行,他们不能修改服务或作为服务用户运行程序。

【讨论】:

    【解决方案4】:

    因为您使用的是 WinForms 和 .Net,所以您的代码将在 MSIL 中可见 - 即使经过混淆,您的解密代码也是可见的。

    您想向谁隐藏密码?应用程序的用户不应该知道密码吗?

    我认为您将需要进行一些用户验证,并且我很想将用于解密的密钥放在单独的数据库中,并提供一些其他机制来获取需要身份验证的密钥。这样您就可以从 winforms 应用程序中获取解密代码。

    我还建议使用单独的服务来定期更改加密解密密钥并更新数据库中的所有密码。

    【讨论】:

      【解决方案5】:

      如果您必须将其存储在文本文件中,则以 AES 加密。

      AES 在 c# 中更广为人知的是 Rijndael

      http://www.obviex.com/samples/Encryption.aspx

      更好的地方是注册表,因为它可以保护机器的其他用户访问它。

      仍然不是最好的将它存储在用户可能到达的任何地方是危险的,一个体面的开发人员可以在反射器中加载您的应用程序并找到您的密钥的 1/2 方式。

      或者有其他人建议的 System.Security.Cryptography.ProtectedData。

      您可以在机器上做的最好的事情是创建一个证书并加密/解密,并将其加载并锁定在机器的密钥库中。 (仍然需要处理代码中的证书密码)

      【讨论】:

      • "更好的地方是注册表,因为它可以保护机器的其他用户访问它。"与文本文件相比,存储在注册表中不会影响机器其他用户的访问。
      • @Joe,机器的其他用户无法访问 HKEY_CURRENT_USER。他们有自己的HKCU。管理员当然被排除在外。 en.wikipedia.org/wiki/Windows_registry 然后是这个:blogs.msdn.com/bclteam/archive/2006/01/06/509867.aspx
      • 但是你是对的,我不喜欢我自己的答案,但由于他必须处理的信息有限,我给了他选择。就个人而言,我喜欢使用 webservice/aspx 为用户代理他的密码,但是他必须获得 SSL 证书等。
      【解决方案6】:

      我刚刚实现了类似的东西来存储用户提供的密码。我将加密结果转换为 base 64 编码字符串,以便我可以轻松地将其存储在我的应用程序的用户设置中。

      从您的问题来看,您的恶意用户似乎实际上正在使用您的应用程序,因此这只会提供混淆。尽管使用 Reflector 不会显示任何密钥,但纯文本将在调试器中可见。

      static byte[] entropy = { 65, 34, 87, 33 };
      
      public string Password
      {
          get
          {
              if (this.EncryptedPassword == string.Empty)
              {
                  return string.Empty;
              }
      
              var encrypted = Convert.FromBase64String(this.EncryptedPassword);
              var data = ProtectedData.Unprotect(encrypted, entropy, DataProtectionScope.CurrentUser);
              var password = Encoding.UTF8.GetString(data);
              return password;
          }
          set
          {
              if (value == string.Empty)
              {
                  this.EncryptedPassword = string.Empty;
                  return;
              }
      
              var data = Encoding.UTF8.GetBytes(value);
              var encrypted = ProtectedData.Protect(data, entropy, DataProtectionScope.CurrentUser);
              var stored = Convert.ToBase64String(encrypted);
              this.EncryptedPassword = stored;
          }
      }
      

      【讨论】:

        【解决方案7】:

        不要将密码存储为代码的一部分。除了反编译和通过隐蔽性依赖安全性的问题之外,如果您更改密码,您需要重新编译和重新分发您的应用程序。

        将密码存储为 Web 服务或应用程序有权访问的数据库中。您正在通过网络与服务进行通信,因此您将始终保持连接。

        【讨论】:

          【解决方案8】:

          其中最重要的是文件的权限。即使内容是加密的,您也需要确保只有需要访问文件的进程才能读取它。

          【讨论】:

            【解决方案9】:

            由于您必须通过网络以未加密的形式发送密码,因此您无法做到 100% 保护它。

            如果您需要在本地存储,AES 就足够了,而且谈论 disasms、网络嗅探器等并不是特别好的反论点,因为同样的事情可以用 any 程序完成(当然,ASM比 CIL 更难,但它是一个小问题)。

            这样的密码保护足以防止随意拿起,而不是防止专业人士解码。

            【讨论】:

            • 就像他说的,它是通过 SSL 加密的
            • 密码用于我使用的另一项服务,需要以明文形式(通过 SSL)发送到那里
            猜你喜欢
            • 2020-05-18
            • 2011-09-23
            • 1970-01-01
            • 2017-04-20
            • 1970-01-01
            • 2010-10-15
            • 2013-05-29
            • 2011-03-26
            • 2014-12-18
            相关资源
            最近更新 更多