我有一个程序使用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;
}
}
答案 0 :(得分:4)
对于salt,我会对用户名进行转换(哈希),而不是为每个人分享相同的盐。
对于类似这样的事情,我还会寻找一种方法来保持现有会话的持续时间,而不是保存密码来创建新会话。
答案 1 :(得分:2)
您应该写new System.Text.ASCIIEncoding()
。
System.Text.Encoding.ASCII
另外,我建议改用UTF8。
除此之外,你的代码看起来还不错。
答案 2 :(得分:0)
我喜欢JoelCoehoorn方法。
使用用户计算机唯一的值作为密码salt。
所以每个部门都会有所不同; )。
更新:请参阅此主题以获取提示:How-To-Get-Unique-Machine-Signature