I've tried to create a remote MySQL database and link it to WPF application. I manage to do that but I was advised by users from the forum to hash my password, cause it can be easyly SQL injected. My question is does anybody know how can I create hashed password based on that code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using MySql.Data.MySqlClient;
namespace ECBSRecruitmentAgencySoftware
{
public partial class LogIn : Form
{
public LogIn()
{
InitializeComponent();
}
public bool tryLogin(string username , string password)
{
MySqlConnection con = new MySqlConnection("host=aaaaaaaa.baaadsg;user=saaaaaak;password=2333333336;database=soaaaaaaaa2;");
MySqlCommand cmd = new MySqlCommand("Select * FROM niki WHERE user_name = `" + username + "` AND user_password = `" + password + "`;");
cmd.Connection = con;
con.Open();
MySqlDataReader reader = cmd.ExecuteReader();
if (reader.Read() != false)
{
if (reader.IsDBNull(0) == true)
{
cmd.Connection.Close();
reader.Dispose();
cmd.Dispose();
return false;
}
else
{
cmd.Connection.Close();
reader.Dispose();
cmd.Dispose();
return true;
}
}
else
{
return false;
}
}
private void button1_Click(object sender, EventArgs e)
{
if (tryLogin(user.Text, pass.Text) == true)
{
MainScreen F2 = new MainScreen();
F2.Show();
this.Hide();
}
else
MessageBox.Show("Wrong details!");
}
}
}
.NET supports several cryptographic hashes including MD5 and SHA so it's quite easy to hash your passwords using ComputeHash
methods of these classes...
Here is a simple example of hashing a file using MD5 which can be easily converted to generate a password hash:
using (var md5 = new MD5CryptoServiceProvider())
{
var buffer = md5.ComputeHash(File.ReadAllBytes(filename));
var sb = new StringBuilder();
for (var i = 0; i < buffer.Length; i++)
{
sb.Append(buffer[i].ToString("x2"));
}
return sb.ToString();
}
Don't forget to salt your hash...
Actually, it would probably be best to just read this great article about storing passwords in a database over on CP...
The Art & Science of Storing Passwords
You would use a hashing algorithm provider, such as SHA256.
var hasher = new SHA256Managed();
var unhashed = System.Text.Encoding.Unicode.GetBytes(password);
var hashed = hasher.ComputeHash(unhashedPassword);
Now, for the sake of storing and comparing in a SQL query, you'd convert the bytes into a string representation, such as Base64Encoded.
var hashedPassword = Convert.ToBase64String(hashed);
Now you can use the value of hashedPassword in your query.
HOWEVER...
You should also consider generating a salt value, either for your entire application, or better yet, per user. You would need a column in the table to store it, and generate it randomly for each user every time the password is changed. Then you'd use something like this to create the hashed password:
static byte[] GenerateSaltedHash(string plainText, string salt)
{
HashAlgorithm algorithm = new SHA256Managed();
byte[] plainTextBytes = System.Text.Encoding.Unicode.GetBytes(plainText);
byte[] saltBytes = Convert.FromBase64String(salt);
byte[] plainTextWithSaltBytes = new byte[plainTextBytes.Length + saltBytes.Length];
salt.CopyTo(plainTextWithSaltBytes, 0);
plainText.CopyTo(plainTextWithSaltBytes, salt.Length);
byte[] hash = algorithm.ComputeHash(plainTextWithSaltBytes);
return hash;
}
Putting it all together...
// omitted
namespace ECBSRecruitmentAgencySoftware
{
public partial class LogIn : Form
{
// omitted
static byte[] GenerateSaltedHash(string plainText, string salt)
{
HashAlgorithm algorithm = new SHA256Managed();
byte[] plainTextBytes = System.Text.Encoding.Unicode.GetBytes(plainText);
byte[] saltBytes = Convert.FromBase64String(salt);
byte[] plainTextWithSaltBytes = new byte[plainTextBytes.Length + saltBytes.Length];
salt.CopyTo(plainTextWithSaltBytes, 0);
plainText.CopyTo(plainTextWithSaltBytes, salt.Length);
byte[] hash = algorithm.ComputeHash(plainTextWithSaltBytes);
return hash;
}
public bool tryLogin(string username , string password)
{
using (var con = new MySqlConnection("host=aaaaaaaa.baaadsg;user=saaaaaak;password=2333333336;database=soaaaaaaaa2;"))
{
con.Open();
var salt = string.Empty;
using (var cmd = new MySqlCommand("Select salt From niki where user_name = @username"))
{
cmd.Parameters.AddWithValue("@username", username);
salt = cmd.ExecuteScalar() as string;
}
if (string.IsNullOrEmpty(salt)) return false;
var hashedPassword = GenerateSaltedHash(password, salt);
using (var cmd = new MySqlCommand("Select * FROM niki WHERE user_name = @username and user_password = @password"))
{
cmd.Parameters.AddWithValue("@username", username);
cmd.Parameters.AddWithValue("@password", hashedPassword);
using (var reader = cmd.ExecuteReader())
{
return reader.Read();
}
}
}
}
// omitted
}
}
Create a function to do it for you:
This is asp.NET
public static string PasswordHasher(string Password)
{
return FormsAuthentication.HashPasswordForStoringInConfigFile(Password,
System.Web.Configuration.FormsAuthPasswordFormat.SHA1);
}
I don't belive your will be able to make secure way of authentication with this code.
First of all you store password to your database in you code. So anyone can use Reflector or any other .NET decompiller to extract password to database. Then, having full connection string, anyone can connect to your database and compromise it (for example, steal all user passwords). Even if your use obfuscation tools, it is still possible to extract this string from your application.
So it is actually does not matter, will you hash user passwords or will you not - anyone can access you system.
The more secure way to perform password validation is creating multi-tired system, so WPF application cannot directly access database, it users Application server to perform any operations with data. For communication you can use web services, WCF. Connection string to your database will be stored only in application server.
Now what about hashes.
You have to find out why do you want to use hash. You can use hash to store it in database (so clear password is not stored anywhere). You can use hash to send password over network, so even if message is intercepted, nobody will find out clear password). Or you can use hash for both this.
If you will store password hash in database, you should research database scheme of build in ASP.NET membership provider.
Based on option you choose, you can implement actual password validation.
Actually it does not really matter how you will compute hash. It just have to be enough strong hash algorithm, for example SHA512 which is buit in in .NET Framework.
.Net has inbuilt support support for MD5 hash algorithm and many other hash algorithm. There is a really good example for this in Microsoft website: https://msdn.microsoft.com/en-us/library/system.security.cryptography.md5(v=vs.110).aspx#Examples .
To learn more about how and why hashing is required you can check out this site: https://www.codeproject.com/Articles/704865/Salted-Password-Hashing-Doing-it-Right