使用Rfc2898DeriveBytes与MSSQL的C#登录系统密码验证异常求助
密码验证不稳定问题排查与解决
你的密码验证时灵时不灵的核心问题,出在错误地用Unicode编码将字节数组(哈希值、salt)转换为字符串存储——这会直接破坏原始字节数据,导致后续验证时无法还原正确的字节序列,自然会出现匹配失败的情况。
问题根源详解
不是所有字节序列都对应有效的Unicode字符。当你用Encoding.Unicode.GetString(byte[])转换字节数组时,无效的字节序列会被自动替换成默认的占位字符(比如�),这就永久性丢失了原始字节信息。把这种失真的字符串存入数据库,再取出来转成字节数组时,已经和最初的哈希、salt字节完全不一样了,验证失败也就成了大概率事件。你后面加的字符串对比偶尔成功只是巧合,根本解决不了本质问题。
修复方案:用Base64编码存储字节数据
Base64是专门为将任意字节序列转换为可打印字符串设计的标准编码,不会丢失任何原始信息,完全适合存储哈希值和salt。
1. 修改新增用户的存储逻辑
把原来的Unicode转换替换成Base64编码:
public SecurityReturnMessage AddUser(string username, string password) { byte[] salt = PasswordManagement.GenerateSalt(); byte[] hashedPassword = PasswordManagement.HashPassword(Encoding.Unicode.GetBytes(password), salt); // 用Base64替代Unicode转换字节数组 string hashPwdBase64 = Convert.ToBase64String(hashedPassword); string saltBase64 = Convert.ToBase64String(salt); using (var conn = new SqlConnection(yourConnectionString)) // 建议用using自动管理连接 { conn.Open(); using (IDbCommand comm = conn.CreateCommand()) { comm.CommandText = "usp_IFRS_SEC_USER_INSERT"; comm.CommandType = CommandType.StoredProcedure; SqlParameter hashPwd = new SqlParameter("@hashpwd", SqlDbType.NVarChar) { Value = hashPwdBase64 }; SqlParameter saltParameter = new SqlParameter("@salt", SqlDbType.NVarChar) { Value = saltBase64 }; comm.Parameters.Add(Extensions.CreateParameter(comm, "@user", username)); comm.Parameters.Add(hashPwd); comm.Parameters.Add(saltParameter); var returnVal = comm.CreateParameter(); returnVal.Direction = ParameterDirection.ReturnValue; comm.Parameters.Add(returnVal); comm.ExecuteNonQuery(); int result = (int)returnVal.Value; return (SecurityReturnMessage)result; } } }
2. 修改密码验证逻辑
从数据库取出Base64字符串后,转回字节数组再对比:
public static bool IsPasswordValid(string inputPassword, string hashedPasswordBase64, string saltBase64) { // 将Base64字符串还原为原始字节数组 byte[] salt = Convert.FromBase64String(saltBase64); byte[] storedHashedPassword = Convert.FromBase64String(hashedPasswordBase64); byte[] inputHashedPassword = HashPassword(Encoding.Unicode.GetBytes(inputPassword), salt); // 只需要对比字节数组即可,无需冗余的字符串对比 return storedHashedPassword.SequenceEqual(inputHashedPassword); }
3. 数据库字段优化建议
确保hashpwd和salt字段的长度足够存储Base64字符串:32字节的原始数据转成Base64后是44字符左右,所以字段长度设为50或100即可,避免字符串被截断。
内容的提问来源于stack exchange,提问作者Robert Woods
相关产品推荐
相关产品推荐

