今天我将我的网络应用程序移动到.net 4.0并且Forms Auth刚刚停止工作。经过几个小时的挖掘我的SqlMembershipProvider(内置SqlMembershipProvider的简化版)后,我发现HMACSHA256哈希不一致。这是加密方法:
internal string EncodePassword(string pass, int passwordFormat, string salt)
{
if (passwordFormat == 0) // MembershipPasswordFormat.Clear
return pass;
byte[] bIn = Encoding.Unicode.GetBytes(pass);
byte[] bSalt = Convert.FromBase64String(salt);
byte[] bAll = new byte[bSalt.Length + bIn.Length];
byte[] bRet = null;
Buffer.BlockCopy(bSalt, 0, bAll, 0, bSalt.Length);
Buffer.BlockCopy(bIn, 0, bAll, bSalt.Length, bIn.Length);
if (passwordFormat == 1)
{ // MembershipPasswordFormat.Hashed
HashAlgorithm s = HashAlgorithm.Create( Membership.HashAlgorithmType );
bRet = s.ComputeHash(bAll);
} else
{
bRet = EncryptPassword( bAll );
}
return Convert.ToBase64String(bRet);
}
传递相同的密码和盐两次返回不同的结果!它在.NET 3.5中完美运行
任何人都知道有任何重大变化,或者这是一个已知的错误?
更新:当我将SHA512指定为散列算法时,一切正常,所以我相信这是在.NET 4.0中实现HMACSHA256散列算法的一个错误
谢谢! 安德烈
答案 0 :(得分:2)
我相信在.net 4.0中有一些与安全相关的变化看看这个......
http://www.asp.net/(S(ywiyuluxr3qb2dfva1z5lgeg))/learn/whitepapers/aspnet4/breaking-changes
第一个显而易见的事情是......
默认哈希算法现在 HMACSHA256
ASP.NET使用加密和 哈希算法有助于保护数据 例如表单身份验证cookie 并查看状态。默认情况下,ASP.NET 4 现在使用HMACSHA256算法 对cookie和视图的哈希操作 州。早期版本的ASP.NET 使用较旧的HMACSHA1算法。
如果您的应用程序可能会受到影响 您运行混合ASP.NET 2.0 / ASP.NET 4 表格等数据的环境 身份验证cookie必须工作 跨.NET Framework版本。至 配置ASP.NET 4 Web应用程序 使用旧的HMACSHA1算法, 在中添加以下设置 Web.config文件:
<machineKey validation="SHA1" />
您是否明确设置了哈希算法或者只是让asp.net决定...如果它现在使用不同的默认值,它可能只是随机抓取任何旧的哈希算法,因为不再支持定义的哈希算法。
话虽如此,M $可能已经退役了你正在使用的那个,所以这可能是原因,开玩笑......我只是意识到我需要测试我的CMS ......这对我来说没有发生过。
感谢您的提醒,希望我的想法能帮助我们两个人!
答案 1 :(得分:2)
我也遇到了这个问题。
在我的情况下,最终目标是能够动态设置connectionString(而不是在web.config中进行硬编码)。我这样做是通过下载MS为ASP.NET Providers推出的源代码并更改一些内部功能来获取连接字符串。
然而,这完全适用于.NET 2.0,看起来就像安德烈在上面发布的代码一样。一旦我把它全部到位,我注意到我无法登录我的网站。所以在搜索后我找到了这篇文章。谢谢!
我继续下载.NET Framework 4.0代码并且(如果有人想知道)这里是EncodePassword方法的新版本。我打算将其复制到旧版本的SqlMembershipProvider中,这样我就可以使用新的加密方法,并能够再次登录我的ASP.NET 4.0网站!
private string EncodePassword(string pass, int passwordFormat, string salt)
{
if (passwordFormat == 0) // MembershipPasswordFormat.Clear
return pass;
byte[] bIn = Encoding.Unicode.GetBytes(pass);
byte[] bSalt = Convert.FromBase64String(salt);
byte[] bRet = null;
if (passwordFormat == 1)
{ // MembershipPasswordFormat.Hashed
HashAlgorithm hm = GetHashAlgorithm();
if (hm is KeyedHashAlgorithm) {
KeyedHashAlgorithm kha = (KeyedHashAlgorithm) hm;
if (kha.Key.Length == bSalt.Length) {
kha.Key = bSalt;
} else if (kha.Key.Length < bSalt.Length) {
byte[] bKey = new byte[kha.Key.Length];
Buffer.BlockCopy(bSalt, 0, bKey, 0, bKey.Length);
kha.Key = bKey;
} else {
byte[] bKey = new byte[kha.Key.Length];
for (int iter = 0; iter < bKey.Length; ) {
int len = Math.Min(bSalt.Length, bKey.Length - iter);
Buffer.BlockCopy(bSalt, 0, bKey, iter, len);
iter += len;
}
kha.Key = bKey;
}
bRet = kha.ComputeHash(bIn);
}
else {
byte[] bAll = new byte[bSalt.Length + bIn.Length];
Buffer.BlockCopy(bSalt, 0, bAll, 0, bSalt.Length);
Buffer.BlockCopy(bIn, 0, bAll, bSalt.Length, bIn.Length);
bRet = hm.ComputeHash(bAll);
}
} else {
byte[] bAll = new byte[bSalt.Length + bIn.Length];
Buffer.BlockCopy(bSalt, 0, bAll, 0, bSalt.Length);
Buffer.BlockCopy(bIn, 0, bAll, bSalt.Length, bIn.Length);
bRet = EncryptPassword(bAll, _LegacyPasswordCompatibilityMode);
}
return Convert.ToBase64String(bRet);
}
编辑:尝试将这一方法复制到旧版本的SqlMembershipProvider是一个坏主意。太多变了。 :(