Bcrypt Password login fail not work MySql C#
AbeidDEV opened this issue · 7 comments
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();
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.
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.
Tried which returns a bool but failed to connect to db, VS2022
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
- https://www.codeguru.com/dotnet/using-sqlite-in-a-c-application/
- https://learn.microsoft.com/en-us/xamarin/android/data-cloud/data-access/using-sqlite-orm
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
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
- 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;");
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;
}
}
No problem