【问题标题】:What to do when you can not save a password as a hash当您无法将密码另存为哈希时该怎么办
【发布时间】:2011-01-17 10:13:57
【问题描述】:

我有一个程序,它使用System.DirectoryServices.AccountManagement.PrincipalContext 来验证用户在设置屏幕中输入的信息是否是域中的有效用户(计算机本身不在域中)并对领域。问题是我不希望用户在每次运行程序时都需要输入他或她的密码,所以我想保存它,但我不喜欢将密码以纯文本形式存储在他们的 app.config 文件中。 PrincipalContext 需要一个纯文本密码,所以我不能像每个人都建议的那样进行加盐哈希来存储密码。

这就是我所做的

const byte[] mySalt = //It's a secret to everybody.
[global::System.Configuration.UserScopedSettingAttribute()]
public global::System.Net.NetworkCredential ServerLogin
{
    get
    {
        var tmp = ((global::System.Net.NetworkCredential)(this["ServerLogin"]));
        if(tmp != null)
            tmp.Password = new System.Text.ASCIIEncoding().GetString(ProtectedData.Unprotect(Convert.FromBase64String(tmp.Password), mySalt, DataProtectionScope.CurrentUser));
        return tmp;
    }
    set
    {
        var tmp = value;
        tmp.Password = Convert.ToBase64String(ProtectedData.Protect(new System.Text.ASCIIEncoding().GetBytes(tmp.Password), mySalt, DataProtectionScope.CurrentUser));
        this["ServerLogin"] = value;
    }
}

这是正确的做法还是有更好的方法?

编辑—— 这是根据大家的建议更新的版本

private MD5 md5 = MD5.Create();

[global::System.Configuration.UserScopedSettingAttribute()]
public global::System.Net.NetworkCredential ServerLogin
{
    get
    {
        var tmp = ((global::System.Net.NetworkCredential)(this["ServerLogin"]));
        if(tmp != null)
            tmp.Password = System.Text.Encoding.UTF8.GetString(ProtectedData.Unprotect(Convert.FromBase64String(tmp.Password), md5.ComputeHash(System.Text.Encoding.UTF8.GetBytes(tmp.UserName.ToUpper())), DataProtectionScope.CurrentUser));
        return tmp;
    }
    set
    {
        var tmp = value;
        tmp.Password = Convert.ToBase64String(ProtectedData.Protect(System.Text.Encoding.UTF8.GetBytes(tmp.Password), md5.ComputeHash(System.Text.Encoding.UTF8.GetBytes(tmp.UserName.ToUpper())), DataProtectionScope.CurrentUser));
        this["ServerLogin"] = tmp;
    }
}

【问题讨论】:

  • 你想保护谁和什么密码?
  • 我会说“正确”的方式是保留 Kerberos 票证,但我不知道在这种情况下如何处理,抱歉。
  • @Slaks - 我正在为那些坐在别人电脑前的无聊同事保护密码。我只想保护不经意的观察者,而不是坚定的黑客。

标签: c# encryption passwords


【解决方案1】:

对于盐,我会对用户名进行转换(散列),而不是为每个人共享相同的盐。

对于这样的事情,我还想寻找一种方法来让现有会话保持更长时间,而不是保存密码来创建新会话。

【讨论】:

  • 会话在程序运行的整个实例中都处于活动状态,我只需要在程序启动时与服务器创建会话,还是您的意思是在运行之间保持会话处于活动状态?
  • 您可以使用服务或其他后台程序来保持会话并使其保持更长时间。
【解决方案2】:

你应该写System.Text.Encoding.ASCII,而不是new System.Text.ASCIIEncoding()

另外,我建议改用 UTF8。

除此之外,您的代码看起来还不错。

【讨论】:

  • 感谢您提供有关使用编码器的其他方式的提示。为什么推荐 UTF8 而不是 ASCII?
  • Joel 使用每个用户名盐的想法是一个很好的建议,我强烈推荐它。
【解决方案3】:

我喜欢 JoelCoehoorn 的方法。

使用对用户机器唯一的值作为密码盐。

所以每个部署都会有所不同; )。

更新:请参阅此线程以获取想法:How-To-Get-Unique-Machine-Signature

【讨论】:

  • 同一个用户登录不同机器是什么意思?它必须是每个用户的。
  • 嗨 Joel 感谢您的提问:) 如果用户从 pc 更改为 pc:在缓存之前,他必须再次输入其域凭据; )
  • 可以是用户也可以是机器。这就是最后一个参数 DataProtectionScope 的用途。
  • 是的,但是由于机器不在域中,所以即使是 per-user 也将是 per-machine。
猜你喜欢
  • 1970-01-01
  • 2011-10-23
  • 2012-05-11
  • 1970-01-01
  • 1970-01-01
  • 2012-08-19
  • 1970-01-01
  • 1970-01-01
  • 2012-10-10
相关资源
最近更新 更多