无法使用vb.net从mysql验证bcrypt-hashed密码

时间:2015-03-21 13:33:10

标签: mysql vb.net authentication bcrypt.net

我在vb.net中有一个使用mysql作为数据库的应用程序。该应用程序有一个登录表单。还有一个注册表,可以使用bcrypt.net在存档中输入新密码,如本网站所示:

  

http://derekslager.com/blog/posts/2007/10/bcrypt-dotnet-strong-password-hashing-for-dotnet-and-mono.ashx

这是我注册新用户的代码(公共程序Clean用于清理表单):

 Private Sub btSignUp_Click(sender As Object, e As EventArgs) Handles btSignUp.Click
dim hash as string
        hash = HashPassword(txConfirmPass.Text)
        If (txPass.Text <> txConfirmPass.Text) Then
            MessageBox.Show("Passwords don't matches")
        Else
            Dim sql As String = "INSERT INTO fusion_login(name,user,password) VALUES (@name,@user,@pass)"
            Using myconnection As MySqlConnection = Connection.getInstance.getConnection()
                Using mycommand As New MySqlCommand()
                    With mycommand
                        .CommandText = sql
                        .CommandType = CommandType.Text
                        .Connection = myconnection
                        .Parameters.Add("@name", MySqlDbType.VarChar).Value = txName.Text
                        .Parameters.Add("@user", MySqlDbType.VarChar).Value = txUser.Text
                        .Parameters.Add("@pass", MySqlDbType.VarChar).Value = hash
                    End With
                    Try
                        myconnection.Open()
                        mycommand.ExecuteNonQuery()
                        If (MessageBox.Show("Do you insert a new user again?", "Register", MessageBoxButtons.YesNo, MessageBoxIcon.Question) = Windows.Forms.DialogResult.Yes) Then 
                            Clean(Me)
                        Else
                            Me.Hide()
                            Login.Show()
                        End If
                    Catch ex As MySqlException
                        MessageBox.Show("Error: " + ex.ToString)
                    Finally
                        myconnection.Close()
                    End Try
                End Using
            End Using
        End If
    End Sub

此代码有效!

现在我正在尝试实现验证使用上述过程创建的用户的代码,但我无法使其工作。以下是我到目前为止的情况:

      Private Sub btLogin_Click(sender As Object, e As EventArgs) Handles btLogin.Click
Dim hash as String
hash = HashPassword(txPass.text)
                Dim sql As String = "SELECT  user,password FROM fusion_login WHERE user = @user AND password = @pass"
                Using myconnection As MySqlConnection = Connection.getInstance.getConnection()
                    Using mycommand As New MySqlCommand()
                        With mycommand
                            .CommandText = sql
                            .CommandType = CommandType.Text
                            .Connection = myconnection
                            .Parameters.Add("@user", MySqlDbType.VarChar).Value = txUser.Text
                            .Parameters.Add("@pass", MySqlDbType.VarChar).Value = hash
                        End With
                        Try
    myconnection.Open()
                        myreader = mycommand.ExecuteReader
                        If myreader.HasRows = 0 Then
                            Me.Hide()
                            FusionPrincipal.Show()
                        Else
                            MessageBox.Show("Error", "Login", MessageBoxButtons.OK, MessageBoxIcon.Warning)
                            txUser.Focus()
                        End If

                        Catch ex As MySqlException
                            MessageBox.Show("Error: " + ex.ToString)
                        Finally
                            myconnection.Close()
                            myreader.Close()
                        End Try
                    End Using
                End Using

我不确定我是否输错了密码,或者在登录时比较用户名/密码错误。这可能是什么问题?

2 个答案:

答案 0 :(得分:1)

问题在于这一行:

If myreader.HasRows = 0 Then

在此代码中,myreader.HasRows是布尔值,但0是整数。要进行此比较,必须首先将0值隐式转换为布尔值。将0转换为布尔值会导致False。这意味着如果数据读取器没有返回任何结果,代码将只输入If块。我相信这与你想要发生的事情相反。相反,只需这样做:

If myreader.HasRows = True Then

或者,甚至更好:

If myreader.HasRows Then

虽然我在这里,但仅仅哈希密码是不够的。您还需要为每个用户设置salt值,并在创建哈希之前将其与密码组合。在对用户进行身份验证时,您会检索该用户名的salt,将其与提供的密码合并,然后将其与结果进行比较。密码比较代码看起来应该更像这样:

Public Function AuthenticateUser(ByVal Username As String, ByVal Password As String) As Boolean
    Dim sql As String = "SELECT  user,password,salt FROM fusion_login WHERE user = @user"
    Using myconnection As MySqlConnection = Connection.getInstance.getConnection(), _
          mycommand As New MySqlCommand(sql, myconnection)

        Try
            mycommand.Parameters.Add("@user", MySqlDbType.VarChar).Value = Username
            myconnection.Open()
            Using rdr As MySqlDataReader = mycommand.ExecuteReader()
                If Not rdr.Read() Then Return False
                Return HashPassword(Password, rdr("salt")).Equals(rdr("password"))
            End Using
        Catch 'You probably want to do more here, but "Return False" was enough for this quick example
             Return False
        End Try
    End Using
End Function

当然,您还需要更新HashPassword()函数以允许其他参数,您的插入代码首先生成salt,并且您的数据库表有空间来存储值。

还有一件事......即使这不完全正确。如果你真的想要做得对,你需要确保明文密码只用SecureString对象保存在内存中。

答案 1 :(得分:1)

找到了这种情况的解决方案:

If mydatareader.Hasrows Then
   While mydatareader.Read
       If (Bcrypt.Net.Bcrypt.Verify(txtPassword.text, mydatareader.Item("password"))) then
           MsgBox("Valid Credentials")
       else
           MsgBox("Invalid Credentials")
       End if
   End While
  mydatareader.Close()
End If