【问题标题】:Hashing password to SqlServer散列密码到 SqlServer
【发布时间】:2013-10-05 15:56:10
【问题描述】:

我一直在一遍又一遍地阅读代码以查看错误发生在哪里,但我无法找到它。我已经从 stackoverflow 复制了这段代码,但从未真正检查过它或完全理解它以修复它。 我正在从 web 服务接收密码、散列、加盐并将其保存到 SqlServer 2008。 SqlServer 上的变量声明为 mail 为 nvarchar(64),hash 为 varbinary(128),salt 为 varbinary(128)。 密码正在保存,但是当我尝试检查密码是否正确时,该方法总是返回 false。 这是我的方法。

public int InsertData(string mail,string Password)
    {

        int lineas;
        UserData usuario = HashPassword(Password);
        using (SqlConnection connection = new SqlConnection(Connection))
        using (SqlCommand command = connection.CreateCommand())
        {
            command.CommandText = "INSERT INTO Usuarios (Mail,Hash,Salt) VALUES (@mail,@hash,@salt)";

            command.Parameters.AddWithValue("@mail", mail);
            command.Parameters.AddWithValue("@hash", usuario.Password);
            command.Parameters.AddWithValue("@salt", usuario.salt);


            connection.Open();
            lineas=command.ExecuteNonQuery();
        }
        usuario = null;
        return lineas;
    }



private UserData HashPassword(string Password)
    {
        //This method hashes the user password and saves it into the object UserData
        using (var deriveBytes = new Rfc2898DeriveBytes(Password, 20))
        {
            byte[] salt = deriveBytes.Salt;
            byte[] key = deriveBytes.GetBytes(20);  // derive a 20-byte key
            UserData usuario = new UserData();
            usuario.Password = key;
            usuario.salt = salt;
            return usuario;

        }


    }

下一个方法是我用来验证密码的方法,它总是返回 false

private bool CheckPassword(string Password, byte[] hash, byte[] salt)
    {


        // load salt and key from database

        using (var deriveBytes = new Rfc2898DeriveBytes(Password, salt))
        {
            byte[] newKey = deriveBytes.GetBytes(20);  // derive a 20-byte key

            if (!newKey.SequenceEqual(hash))
                return false;

            else
                return true;

        }
    }

此方法接收登录信息

 public bool ValidateLogIn(string mail, string Password)
    {



        using (SqlConnection connection = new SqlConnection(Connection))
        using (SqlCommand command = connection.CreateCommand())
        {
            command.CommandText = "Select * from Usuarios where Mail=@mail";
            command.Parameters.AddWithValue("@mail",mail);
            connection.Open();
            using (SqlDataReader reader = command.ExecuteReader())
            {
                reader.Read();
                byte[] hash = (byte[])reader["Hash"];
                byte[] salt = (byte[])reader["Salt"];
                if(CheckPassword(Password,hash,salt))
                {
                    /
                    UpdateData(mail, Password);
                    return true;
                }
                else
                {
                    return false;
                }

            }

        }

    }

有什么想法可能是错的吗?

编辑:我找到了获得哈希码的链接 https://stackoverflow.com/a/4330586/1861617

【问题讨论】:

  • 保存和验证数据时,hash 和 salt 是否相同?
  • 是的,我将哈希值和盐值保存到同一行。然后加载同一行并根据密码验证它
  • 您是否尝试过在代码中的任何位置设置断点并跟踪执行到 100% 以确保变量保持您认为它们保持的状态(并验证代码的行为是否符合预期)?另外,您是否收到任何错误?
  • 没有错误,我会尝试一步一步调试它,看看我可能缺少什么

标签: c# sql-server sql-server-2008 hash salt


【解决方案1】:

在测试项目中使用您的代码(带有文本框+按钮+标签的 Windows 窗体)我添加了这个:

   internal class UserData
    {
        public byte[] Password { get; set; }
        public byte[] Salt { get; set; }
    }

    public string Connection { get; set; }

    private void UpdateData(string mail, string password)
    {
        // not a clue what to do here....
    }

    private void button1_Click(object sender, EventArgs e)
    {
        var password = textBox1.Text;
        var u = HashPassword(password);

        var b = new SqlConnectionStringBuilder {DataSource = "127.0.0.1", IntegratedSecurity = true};
        Connection = b.ConnectionString;

        InsertData("test@domain.com", password);

        label1.Text = string.Format("Using direct check: {0}\nVia the database: {1}", 
            CheckPassword(password, u.Password, u.Salt),
            ValidateLogIn("test@domain.com", password));
    }

它返回 true;true 没有任何问题。 (VS2010、.Net4 CP、SQL2008R2)

在我使用的数据库上:

CREATE TABLE tempdb..t_hash 
    (
        Mail nvarchar(64) NOT NULL PRIMARY KEY (Mail), 
        Hash varbinary(128), 
        Salt varbinary(128)
     )

我最好的猜测是您对 UserData 类的定义是“有缺陷的”?

【讨论】:

    【解决方案2】:

    在检查了德罗比的答案后,仍然没有运气。我重新检查并意识到 20 个字节是 120 位,因此 varbinary 无法存储整个盐。将其增加到 256 后,它起作用了。

    【讨论】:

      猜你喜欢
      • 2011-02-18
      • 2013-04-24
      • 1970-01-01
      • 1970-01-01
      • 2015-08-13
      • 2012-05-30
      • 1970-01-01
      • 2019-07-23
      • 2011-06-23
      相关资源
      最近更新 更多