BcryptNet / bcrypt.net

BCrypt.Net - Bringing updates to the original bcrypt package
MIT License
824 stars 98 forks source link

Bcrypt Password login fail not work MySql C# #130

Closed AbeidDEV closed 1 year ago

AbeidDEV commented 1 year ago
            try
            {
                Connection con = new Connection ();
                con.Open();
                string query = "SELECT `username`, `password` FROM `MyDatabase_Users` WHERE username='" + tBUsername.Text + "' AND password= '" +BCryptNet.Verify( textBoxPASSWORD.Text)+ "'";
                MySqlDataReader row;
                row = con.ExecuteReader(query);
                if (row.HasRows)
                {

                    //logged in
                    MessageBox.Show("You have been logged in");

                }
                else
                {
                     //Failed logged in
                    MessageBox.Show("Incorrect password or user");

} } catch (Exception ex) { MessageBox.Show("No network"); }

            con.Close();
ChrisMcKee commented 1 year ago

password= '" +BCryptNet.Verify( textBoxPASSWORD.Text)+ "'"

You're using verify; which returns a bool; in a sql statement and without the hash to compare it against.

The entire things not valid.

ChrisMcKee commented 1 year ago

I'd advise against handling sql like that.

You might find it easier to use something like entity framework which will provide some guard-rails as well as allowing you to skip writing sql and use the linq provider to query data. Also https://jonathancrozier.com/blog/preventing-sql-injection-in-c-sharp-applications

You would need to query the password from sql; then call Verify like BCrypt.Verify("my password from txtbox", passwordHashFromSql); and use the bool response to fail or allow the login.

AbeidDEV commented 1 year ago

Tried which returns a bool but failed to connect to db, VS2022

ChrisMcKee commented 1 year ago

I'm guessing you're new to this and its related to the repo in your account. I'll try to break the bits down.

Version control You should really just put the files in rather than a zip; gits great at letting you see the history of your changes but sadly in a zip which is basically an opaque binary to git it wont do a whole lot.

Winforms & SQL Firtly if you're interested in desktop apps I'd look at the newer stuff https://learn.microsoft.com/en-us/dotnet/maui/what-is-maui?view=net-maui-7.0 I'll openly admit to still cracking out winforms on occasion but it's pretty much on the way out in the grand scheme of things.

If your aim is to store data locally for a user and the querying isn't particularly complex you may wish to consider using something like SQLLite instead of a full blown SQL engine like MySql

Of course if you're talking to a remote sql server that's a whole different thing.

Your repo

Assuming I'm right about the winforms app; I've pulled your zip; modified the code to use bcrypt so you have an example

C#_Login_Encrypt.zip

There's a docker-compose file in there (docker-compose up -d) which will start mysql locally with the passwords configured etc. The sql class is setup to bootstrap the table.

...
        public MySqlDb()
        {
            SqlConnection = new MySqlConnection($"Server={Server};Database={Database};User ID={Uid};Password={Password}");
            SqlConnection.Open();

            if (BootStrapSql) return;

            using var tblCheck = SqlConnection.CreateCommand();
            tblCheck.CommandText = @$"
CALL sys.table_exists({Database}, users, @table_type); 
SELECT @table_type;
";
            var reader = tblCheck.ExecuteReader();
            if (!reader.Read())
            {
                using var tblCommand = SqlConnection.CreateCommand();
                tblCommand.CommandText = @"CREATE TABLE IF NOT EXISTS users
                                    (
                                      Id int(10) NOT NULL,
                                      userName varchar(20) NOT NULL,
                                      Password varbinary(256) NOT NULL,
                                      Registered varchar(20) DEFAULT NULL
                                    );
                                    ALTER TABLE users
                                      ADD PRIMARY KEY (Id),
                                      ADD UNIQUE KEY userName (userName);

                                    ALTER TABLE users
                                      MODIFY Id int(10) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=24;
                                    COMMIT;           
            ";
                tblCommand.ExecuteNonQuery();
            }
            BootStrapSql = true;
        }

It's not how I'd do this in production but for the sake of example it does the job.

The user creation changes to

...
            try
            {
                using MySqlDb db = new MySqlDb();

                using var cmd = db.SqlConnection.CreateCommand();

                cmd.CommandText = "INSERT INTO users (Username, Password, Registered) values (@name, @password, now())";
                cmd.Parameters.AddWithValue("@name", userName);
                cmd.Parameters.AddWithValue("@password", BCrypt.Net.BCrypt.HashPassword(password));
                cmd.ExecuteNonQuery();

                System.Windows.Forms.MessageBox.Show("Account created", "Information", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Information);

                return $"{userName}{password}";
            }
            catch (Exception ex)
            {
                System.Windows.Forms.MessageBox.Show(ex.Message, "Information", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Warning);
                return null;
            }
...

So we take the input password from the user and we hash it as its stored.

To validate it we'd call ValidateLogin

...
try
            {
                using MySqlDb db = new MySqlDb();

                using var cmd = db.SqlConnection.CreateCommand();
                cmd.CommandText = ("Select Top 1 Username, Password  from users where userName = @name;");
                cmd.Parameters.AddWithValue("@name", userName);

                var reader = cmd.ExecuteReader();

                if (!reader.Read())
                {
                    System.Windows.Forms.MessageBox.Show("Error", "Information",
                        System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
                }
                else
                {
                    while (reader.Read())
                    {
                        var sqlPassword = reader.GetString(1);

                        if (BCrypt.Net.BCrypt.Verify(password, sqlPassword))
                        {

                            System.Windows.Forms.MessageBox.Show("Hi :D", "Information",
                                System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Information);
                        }
                        else
                        {
                            System.Windows.Forms.MessageBox.Show("Error", "Information",
                                System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
                        }
                    }
                }

                return $"{userName}{password}";
            }
            catch (Exception ex)
            {
                System.Windows.Forms.MessageBox.Show(ex.Message, "Information", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Warning);
                return null;
            }

        }
AbeidDEV commented 1 year ago

Thank you, for support

On Fri, 17 Feb 2023, 13:34 Chris McKee, @.***> wrote:

I'm guessing you're new to this and its related to the repo in your account. I'll try to break the bits down.

Version control You should really just put the files in rather than a zip; gits great at letting you see the history of your changes but sadly in a zip which is basically an opaque binary to git it wont do a whole lot.

Winforms & SQL Firtly if you're interested in desktop apps I'd look at the newer stuff https://learn.microsoft.com/en-us/dotnet/maui/what-is-maui?view=net-maui-7.0 I'll openly admit to still cracking out winforms on occasion but it's pretty much on the way out in the grand scheme of things.

If your aim is to store data locally for a user and the querying isn't particularly complex you may wish to consider using something like SQLLite instead of a full blown SQL engine like MySql

Of course if you're talking to a remote sql server that's a whole different thing.

Your repo

Assuming I'm right about the winforms app; I've pulled your zip; modified the code to use bcrypt so you have an example

C#_Login_Encrypt.zip https://github.com/BcryptNet/bcrypt.net/files/10765728/C._Login_Encrypt.zip

There's a docker-compose file in there (docker-compose up -d) which will start mysql locally with the passwords configured etc. The sql class is setup to bootstrap the table.

... public MySqlDb() { SqlConnection = new MySqlConnection($"Server={Server};Database={Database};User ID={Uid};Password={Password}"); SqlConnection.Open();

        if (BootStrapSql) return;

        using var tblCheck = SqlConnection.CreateCommand();
        tblCheck.CommandText = @$"CALL sys.table_exists({Database}, users, @table_type); SELECT @table_type;";
        var reader = tblCheck.ExecuteReader();
        if (!reader.Read())
        {
            using var tblCommand = SqlConnection.CreateCommand();
            tblCommand.CommandText = @"CREATE TABLE IF NOT EXISTS users                                    (                                      Id int(10) NOT NULL,                                      userName varchar(20) NOT NULL,                                      Password varbinary(256) NOT NULL,                                      Registered varchar(20) DEFAULT NULL                                    );                                    ALTER TABLE users                                      ADD PRIMARY KEY (Id),                                      ADD UNIQUE KEY userName (userName);                                    ALTER TABLE users                                      MODIFY Id int(10) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=24;                                    COMMIT;                       ";
            tblCommand.ExecuteNonQuery();
        }
        BootStrapSql = true;
    }

It's not how I'd do this in production but for the sake of example it does the job.

The user creation changes to

... try { using MySqlDb db = new MySqlDb();

            using var cmd = db.SqlConnection.CreateCommand();

            cmd.CommandText = "INSERT INTO users (Username, Password, Registered) values ***@***.***, @password, now())";
            ***@***.***", userName);
            ***@***.***", BCrypt.Net.BCrypt.HashPassword(password));
            cmd.ExecuteNonQuery();

            System.Windows.Forms.MessageBox.Show("Account created", "Information", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Information);

            return $"{userName}{password}";
        }
        catch (Exception ex)
        {
            System.Windows.Forms.MessageBox.Show(ex.Message, "Information", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Warning);
            return null;
        }

...

So we take the input password from the user and we hash it as its stored.

To validate it we'd call ValidateLogin

  • Which selects the first match on username
  • extracts the password hash from the results
  • Passes the hash to bcrypt with the user entered password.
  • BCrypt then uses the SALT portion of the hash to hash the user-entered password in exactly the same way as when it was generated
  • If the two strings match (if you look at the bcrypt code you'll see we do this in a de-optimized fashion to try and ensure timing attacks dont work)
  • Return pass or fail depending on the verify response

... try { using MySqlDb db = new MySqlDb();

            using var cmd = db.SqlConnection.CreateCommand();
            cmd.CommandText = ("Select Top 1 Username, Password  from users where userName = @name;");
            ***@***.***", userName);

            var reader = cmd.ExecuteReader();

            if (!reader.Read())
            {
                System.Windows.Forms.MessageBox.Show("Error", "Information",
                    System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
            }
            else
            {
                while (reader.Read())
                {
                    var sqlPassword = reader.GetString(1);

                    if (BCrypt.Net.BCrypt.Verify(password, sqlPassword))
                    {

                        System.Windows.Forms.MessageBox.Show("Hi :D", "Information",
                            System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Information);
                    }
                    else
                    {
                        System.Windows.Forms.MessageBox.Show("Error", "Information",
                            System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
                    }
                }
            }

            return $"{userName}{password}";
        }
        catch (Exception ex)
        {
            System.Windows.Forms.MessageBox.Show(ex.Message, "Information", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Warning);
            return null;
        }

    }

— Reply to this email directly, view it on GitHub https://github.com/BcryptNet/bcrypt.net/issues/130#issuecomment-1434446970, or unsubscribe https://github.com/notifications/unsubscribe-auth/A5NZW4QDHNBAGIRZS7FXWG3WX5H4BANCNFSM6AAAAAAU56J4XI . You are receiving this because you authored the thread.Message ID: @.***>

ChrisMcKee commented 1 year ago

No problem

AbeidDEV commented 1 year ago

Great, thanks!

On Fri, 17 Feb 2023, 15:14 Chris McKee, @.***> wrote:

No problem

— Reply to this email directly, view it on GitHub https://github.com/BcryptNet/bcrypt.net/issues/130#issuecomment-1434557454, or unsubscribe https://github.com/notifications/unsubscribe-auth/A5NZW4WSAAWURLP5CDVJUHTWX5TRDANCNFSM6AAAAAAU56J4XI . You are receiving this because you authored the thread.Message ID: @.***>