i'm trying to update my database with a new hashed password on asp.net with a change password form,but it isn't working nor giving me errors.
I'm using bcrypt for hashing.Registration and Login are working just fine,but changing the hashed password is difficult.
SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["dbconnection"].ConnectionString);
con.Open();
//Select
string query = "select password from Users where name=#name";
SqlCommand cmd = new SqlCommand(query, con);
cmd.Parameters.AddWithValue("#password", txtOld.Text.Trim());
cmd.Parameters.AddWithValue("#name", LblUser.Text);
//Update
try {
string queryupdate = "UPDATE Users SET password=#newpassword WHERE name=#name";
SqlCommand cmd1 = new SqlCommand(queryupdate, con);
string salt = BCr.BCrypt.GenerateSalt(12);
// if you look at the hashed password, notice that it's prepended with the salt generated above
string hashedPassword = BCr.BCrypt.HashPassword(txtConfirm.Text.Trim(), salt);
cmd1.Parameters.AddWithValue("#name", LblUser.Text);
cmd1.Parameters.AddWithValue("#newpassword", hashedPassword);
cmd1.Parameters.AddWithValue("#password", txtOld.Text.Trim());
cmd1.ExecuteNonQuery();
LblUser.Text = "Password changed successfully";
LblUser.ForeColor = System.Drawing.Color.Green;
}
catch(Exception ex)
{
LblUser.Text = "Something Went Wrong";
LblUser.ForeColor = System.Drawing.Color.Red;
}
I'm assuming you're using the newer version of the bcrypt library https://www.nuget.org/packages/BCrypt.Net-Next/ rather than the old one with bugs.
Firstly don't generate the salt yourself this is dealt with in the library.
You can generate a new password hash securely by simply calling
var myNewHash = BCrypt.ValidateAndReplacePassword(currentPassword, currentHash, newPassword);
This of course forces the process to require the user to enter their current password in order to change their password (this is best practice).
If you're doing this in the sense of a password reset you should hash the password using
var myNewHash = BCrypt.HashPassword("newpassword");
As documented at the start of the readme https://github.com/BcryptNet/bcrypt.net
As for the SQL element; I'd consider using EF or Dapper.Net over direct ADO manipulation. SQL parameterisation isn't foolproof protection against SQLI Examples of SQL injection even when using SQLParameter in .NET?
If you're using ADO though make sure you specify your parameter types ala
var connect = ConfigurationManager.ConnectionStrings["NorthWind"].ToString();
var query = "Select * From Products Where ProductID = #ProductID";
using (var conn = new SqlConnection(connect))
{
using (var cmd = new SqlCommand(query, conn))
{
cmd.Parameters.Add("#ProductID", SqlDbType.Int);
cmd.Parameters["#ProductID"].Value = Convert.ToInt32(Request["ProductID"]);
conn.Open();
conn.Open();
//Process results
}
}
Disclaimer: I'm the author of the listed repo
Code sample for ADO from https://www.mikesdotnetting.com/article/113/preventing-sql-injection-in-asp-net
Related
I have a simple login website, which is my first website project in Visual Studio 2015. I have successfully created a SQL database which contains user information like Username, Password, Email and Country, and I have also successfully created a user registration page where a new user can input there details and these details will be added to the database. This all works fine.
but I have hit a roadblock while attempting to validate the Username and Password against the stored values in the row containing the User data in the SQLdatabase to give the user access to the member only pages.
Heres my code snippet for when the user click the login button.
SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["MembersConnectionString"].ConnectionString);
con.Open();
string checkUser = "SELECT * FROM Members where Username= '" + TextBoxSignUser.Text + "' and Password= '" + TextBoxSignPass.Text + "'";
SqlCommand cmd = new SqlCommand(checkUser, con);
cmd.ExecuteNonQuery();
con.Close();
I know what I need to do is probably something like this pseudocode below, but I am unsure how to go about validating this information against stored values in the database.
if ("Username" and "Password" == the value of Username and Password TextBox.Text)
{
Response.Write("Sign in successful");
Response.Redirect("MemberTestPage.aspx");
}
else
{
Response.Write("Details incorrect, Please try again")
}
Fill the data-table using data adapter one you get the data into a data-table you can get the return values of the query and match the parameters
DataTable Dt = new Datatable();
SqlDataAdapter sda = new SqlDataAdapter(cmd);
sda.Fill(dt);
if (dt.rows.count > 0 )
{
//MATCH FOUND
}
You can use like..
string query= "SELECT * FROM Members where Username= 'usr' and Password= 'pwd'";
SqlCommand cmd = new SqlCommand(query, con);
MySqlDataAdapter objda = new MySqlDataAdapter(cmd);
DataSet objDs = new DataSet();
objda.Fill(objDs);
if(objDs.Tables[0].Rows.Count>0)
{
Response.Write("Sign in successful");
Response.Redirect("MemberTestPage.aspx");
}
You could do as following without using Datasets,
var con = new SqlConnection("your connection string goes here");
SqlCommand cmd = new SqlCommand("SELECT * FROM Members where Username= 'usr' and Password= 'pwd'", con);
bool result = false;
cmd.Connection.Open();
using (cmd.Connection)
{
SqlDataReader dr = cmd.ExecuteReader();
if (dr.HasRows)
result = true;
}
if (result == true)
// Login successful
else
// Login failed
string query = string.Format("SELECT TOP 1 * FROM [Table] WHERE Username = '{0}' and Password = '{1}'", txtUsername.Text, txtPassword.Text);
command = new OleDbCommand(query, con);
var reader = command.ExecuteReader();
if (reader.HasRows)
{
//successfully login
}
else
//error message
I think first of all it is better to use ADO.NET libraries for some reasons like best performance and high security. Here is my suggestion. hope to be useful for you:
using System.Data.SqlClient;
...
string conStr = ConfigurationManager.ConnectionStrings["MembersConnectionString"].ConnectionString;
string sql = "SELECT * FROM Members where Username = #user and Password = #pass";
SqlParameter pUser = new SqlParameter("#user", TextBoxSignUser.Text);
SqlParameter pPass = new SqlParameter("#pass", TextBoxSignPass.Text);
using (SqlConnection con = new SqlConnection(conStr))
{
using (SqlCommand cmd = new SqlCommand(sql, con))
{
cmd.Parameters.Add(pUser);
cmd.Parameters.Add(pPass);
con.Open();
using (SqlDataReader reader = cmd.ExecuteReader())
{
if (reader.Read())
{
// Successfully signed in
// Also you can access your fields' value using:
// 1. its index (e.x. reader[0])
// 2. or its name: (e.x. reader["Username"])
}
else
{
// Login failed
}
}
}
}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
Yesterday I asked a question about the table you guys helped a lot. Someone suggested that I don't directly store the strConnectionString so I changed what I had.
This is my code:
private void main_B_login_Click(object sender, RoutedEventArgs e)
{
//connect to the database
SqlConnection loginConn = null;
SqlCommand cmd = null;
SqlDataAdapter sda = null;
DataTable dt = new DataTable();
loginConn = new SqlConnection("server=localhost;" + "Trusted_Connection=yes;" + "database=Production; " + "connection timeout=30");
cmd = new SqlCommand("Select Username FROM [User] WHERE Username =#UsernameValue", loginConn);
loginConn.Open();
cmd.CommandType = CommandType.Text;
cmd.Parameters.Add("#UsernameValue", SqlDbType.VarChar).Value = Main_T_Username.Text;
sda = new SqlDataAdapter(cmd);
sda.Fill(dt);
if (dt.Rows.Count > 0)
{
//MessageBox.Show("username");
SqlConnection loginConn2 = null;
SqlCommand cmd2 = null;
SqlDataAdapter sda2 = null;
DataTable dt2 = new DataTable();
loginConn2 = new SqlConnection("server=localhost;" + "Trusted_Connection=yes;" + "database=Production; " + "connection timeout=30");
cmd2 = new SqlCommand("Select Password FROM [User] WHERE Password =#PasswordValue", loginConn2);
loginConn2.Open();
cmd2.CommandType = CommandType.Text;
cmd2.Parameters.Add("#PasswordValue", SqlDbType.VarChar).Value = Main_T_Password.Text;
sda2 = new SqlDataAdapter(cmd2);
sda2.Fill(dt2);
if (dt2.Rows.Count > 0)
{
MessageBox.Show("username and Password = Correct");
}
else
{
MessageBox.Show("Password = Wrong");
loginConn2.Close();
}
}
else
{
MessageBox.Show("WrongPass or Username!");
loginConn.Close();
}
}
At the moment it works perfectly. I am not sure about two things.
Is the connection string now as it stands still "bad" in terms of SQL INJECTION?
I have the code basically check first the username then password..? i have stored them both as text values because I don't know how to change it to hashing.
Could I simplify the check to do both username and password? but still give out and error when the username is wrong and when the password is wrong?
Connection string is not prone to sql injection.
you can check both username and password like this:
cmd = new SqlCommand("Select Username FROM [User] WHERE Username =#UsernameValue AND Password =#PasswordValue", loginConn);
loginConn.Open();
cmd.CommandType = CommandType.Text;
cmd.Parameters.Add("#UsernameValue", SqlDbType.VarChar).Value = Main_T_Username.Text;
cmd2.Parameters.Add("#PasswordValue", SqlDbType.VarChar).Value = Main_T_Password.Text;
firstly is the connection string now as it stands still "bad" in terms
of SQL INJECTION?
The connection string is not relevant.
You are using prepared sql statements , and this is what is good to prevent sql injection.
secondly I have the code basically check first the username then
password..? i have stored them both as text values because I don't
know how to change it to hashing.
Never save passwords as clear text in a DB
You must save an hash of the password to DB.
When a user want to login, compare an hash of the password that the user entered with the hash of the passwords present on DB.
See here for some examples: How to hash a password
Could I simplify the check to do both username and password? but still give out and error when the username is wrong and when the password is wrong?
Yes , you must simplify it.
At the moment you are basically doing 2 hits on DB when you want just one.
You can simply do a select on DB by the username , then if you have 0 rows the username doesn't exists.
Otherwise the username exists and you can compare the password (the hash of the password) the user given to you with the password from the selected row (isn't necessary to do a 2nd select, you have already the row from the previous select).
Something like this (refinement is up to the reader):
private void main_B_login_Click(object sender, RoutedEventArgs e)
{
//connect to the database
SqlConnection loginConn = null;
SqlCommand cmd = null;
SqlDataAdapter sda = null;
DataTable dt = new DataTable();
loginConn = new SqlConnection("server=localhost;" + "Trusted_Connection=yes;" + "database=Production; " + "connection timeout=30");
cmd = new SqlCommand("Select Username, Password FROM [User] WHERE Username =#UsernameValue", loginConn);
loginConn.Open();
cmd.CommandType = CommandType.Text;
cmd.Parameters.Add("#UsernameValue", SqlDbType.VarChar).Value = Main_T_Username.Text;
sda = new SqlDataAdapter(cmd);
sda.Fill(dt);
if (dt.Rows.Count > 0)
{
if ((string) dt.Rows[0]['Password'] == Main_T_Password.Text)
{
MessageBox.Show("username and Password = Correct");
}
else
{
MessageBox.Show("Password = Wrong");
}
}
else
{
MessageBox.Show("WrongPass or Username!");
}
loginConn.Close();
}
For the Connection string part use SqlConnectionStringBuilder class wtih conjuction with your App.Config rather using string manipulation straight on the code.
Public string GetConnectionString()
{
//Read the Application Settings from App.Config
SqlConnectionStringBuilder sqlConstrBuilder = new SqlConnectionStringBuilder();
sqlConstrBuilder.DataSource = dataSource;
sqlConstrBuilder.InitialCatalog = databaseName;
sqlConstrBuilder.UserID = ConfigurationManager.AppSettings["UserId"].ToString();
sqlConstrBuilder.Password = ConfigurationManager.AppSettings["Password"].ToString();
return sqlConstrBuilder.ConnectionString;
}
Move connection string to config file and read it with ConfigurationManager.
Sql Injections is not about connection string, it is about sql command.
Writing sql command in the code is not good practice, move it to stored procedure(Actually using orm is better for most cases). If you want to keep sql command in code, replace single quote with double quote to avoid sql injection.
And last, read more before start coding.
You can do 3 things to improve and simplify your code :
1 - store your configuration string in your web.config or App.config
<connectionStrings>
<add name="ModelDB" connectionString="server=localhost;user id=User;password=Password;port=3333;database=database" providerName="MySql.Data.MySqlClient" />
</connectionStrings>
2 - store the passwords as byte[] in your database and use a hash function (you can use MD5 from System.Security.Cryptography)
using System.Security.Cryptography;
byte[] password = MD5.Create().ComputeHash(Encoding.UTF8.GetBytes(Main_T_Password.Text));
3 - use linq and Ado.Net Entity Data Model to simplify your requests
(look for turotials https://msdn.microsoft.com/en-us/data/ff728653.aspx)
You can then generate C# classes from your database and you will be able to use linq and to treat results from your requests as objects which will simplify the code.
For exemple the ModelDB object below will automatically connect to the mysql database using the connectionString from the Web.config or App.config file.
You can use differents providers depending on your database (use providerName="System.Data.SqlClient" if your are using SQLServer)
ModelDB sql = new ModelDB();
var users = from users in sql.Users where Username = Main_T_Username.Text select users;
if(users.Count() == 0)
MessageBox.Show("WrongPass or Username!");
else if(users.Count() > 0 && users[0].Password.SequenceEqual(password))
MessageBox.Show("username and Password = Correct");
else
MessageBox.Show("Password = Wrong");
I have to make a simple login that will not crash when you insert into the browser a (") so i needed to parameterize the query string but for some reason im gettin an error saying:
Must declare the scalar variable "#UserName"
here is the code
private void DoSqlQuery()
{
try
{
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["RolaConnectionString"].ConnectionString);
conn.Open();
string checkUser = "select * from UserData where UserName = #UserName";
SqlCommand com = new SqlCommand(checkUser, conn);
com.Parameters.AddWithValue("#Username", txtUserName.Text.Trim());
int temp = Convert.ToInt32(com.ExecuteScalar().ToString());
conn.Close();
if (temp == 1)
{
conn.Open();
string checkPassword = "select Password from UserData where UserName = #UserName";
SqlCommand passConn = new SqlCommand(checkPassword, conn);
com.Parameters.AddWithValue("#Username", txtUserName.Text.Trim());
string password = passConn.ExecuteScalar().ToString();
conn.Close();
if (password == txtPassword.Text)
{
Session["New"] = txtUserName.Text;
Response.Write("Password is correct");
Response.Redirect("~/LoggedIn.aspx");
}
else
{
Response.Write("Password is not correct");
}
}
else
{
Response.Write("Username is not correct");
}
}
catch(Exception e)
{
Response.Write(e.ToString());
}
}
You are referencing the wrong command in the inner if statement:
string checkPassword = "select Password from UserData where UserName = #UserName";
SqlCommand passConn = new SqlCommand(checkPassword, conn);
com.Parameters.AddWithValue("#Username", txtUserName.Text.Trim());
^^^-- should be passConn
As a result, your second command never gets the parameter added so you get the error you mention. Case sensitivity may also be a problem, but it depends on the collation of your database - SQL Server is case-insensitive by default.
Some other suggestions not related to your problem:
Wrap commands and connection in using statements
Query the username and password in one query (WHERE UserName = #UserName AND Password = #Password). Hackers will first search for valid usernames, then try to hack the password using dictionary attacks. Trying to find a matching combination is much harder.
Do not store your passwords in plain text - use a salted hash
Or just use built-in security providers rather than rolling your own.
I'm doing an application for school and I'm in need of help in encrypting passwords when inserting them into my users database.I'm programming in c# programming language and i'm using MS server 2008 R2 for manipulating my database. I'm thinking of doing a HASH encryption and I would love if someone helped me out.
Here's my code for inserting data into database :
using (SqlConnection con = new SqlConnection("Data Source=HRC0;Initial Catalog=users;Integrated Security=True")) //MLHIDE
using (SqlCommand sc = new SqlCommand("if NOT exists (select * from users where UserName = #username) insert into users (userName, password) values(#userName, #password)", con))
{
con.Open();
sc.Parameters.AddWithValue("#username", korisnik.Text);
sc.Parameters.AddWithValue("#password", pass.Text);
int o = sc.ExecuteNonQuery();
if (o == -1)
{
MessageBox.Show(Ulaz.Properties.Resources.Niste_ubačeni_u_bazi_korisničk);
this.Hide();
new Registracija().Show();
}
else
{
MessageBox.Show(Ulaz.Properties.Resources.Ubačeni_ste_u_bazi);
con.Close();
this.Hide();
new Form1().Show();
}
and here's my code for login check :
SqlConnection con = new SqlConnection("Data Source=HRC0;Initial Catalog=users;Integrated Security=True");
SqlCommand cmd = new SqlCommand("select * from users where userName='" + user.Text + "' and password='" + pass.Text + "'", con); //MLHIDE
con.Open();
SqlDataReader re = cmd.ExecuteReader();
if (re.Read())
{
ImeUsera = user.Text;
new UserMode().Show();
this.Hide();
}
else
{
this.Hide();
new LoginFail().Show();
}
}
I used some Multi-Language add-on so he converted my strings into ''Ulaz.Properties.Resources.'' and simmilar.
To hash a string of text you could use a function like this
private string GetHashedText(string inputData)
{
byte[] tmpSource;
byte[] tmpData;
tmpSource = ASCIIEncoding.ASCII.GetBytes(inputData);
tmpData = new MD5CryptoServiceProvider().ComputeHash(tmpSource);
return Convert.ToBase64String(tmpData);
}
and apply to your user input. Then store the result in the database. At login you reapply the hash function to the typed password and check the result against the stored value.
So in your insert code you write
sc.Parameters.AddWithValue("#password", GetHashedText(pass.Text));
and in your check
....
SqlCommand cmd = new SqlCommand("select * from users where userName=#user and password=#pass", con);
con.Open();
cmd.Parameters.AddWithValue("#user",user.Text);
cmd.Parameters.AddWithValue("#pass", GetHashedText(pass.Text));
SqlDataReader re = cmd.ExecuteReader();
if (re.Read())
.....
Remember that Hashing is not reversible, so you cannot retrieve the original password from the hashed text. You apply the Hash function to your text and store it as a base64 string. If your user forgets the password, you need to reset it to a known value. There is no way to tell him the original password.
By the way, why in your check you don't use parameters as you do in the insert code? Never use string concatenation to build sql queries. Even if you're in a hurry to finish the job
I have the following code in my btn_click event:
Sqlconnection con = new Sqlconnection("server=.;database=bss;user id=ab;pwd=ab");
con.open();
SqlCommand cmd = new Sqlcommand("select * from login where username='"
+ txt4name.Text + "' and pwd='" + txt4pwd.Text + "'", con);
SqlDataReader reader = cmd.execute Reader();
Where login is the table and username and pwd are its fields. After this code all the values are stored in the reader object. I want to store username and pwd in the separate variables.
How can I accomplish this?
In general, when accessing your DB, you should be using something similar to this instead to eliminate SQL injection vulnerabilities:
using (SqlCommand myCommand = new SqlCommand("SELECT * FROM USERS WHERE USERNAME=#username AND PASSWORD=HASHBYTES('SHA1', #password)", myConnection))
{
myCommand.Parameters.AddWithValue("#username", user);
myCommand.Parameters.AddWithValue("#password", pass);
myConnection.Open();
SqlDataReader myReader = myCommand.ExecuteReader())
...................
}
But more realistically to store credentials, you should be using something like the Membership system instead of rolling your own.
You're running a huge risk of sql injection with that. Use SQL Parameters for values into SqlCommands.
If you mean c# variables, and if you want to get them from db, just do this:
SqlDataReader reader = cmd.execute Reader();
if (reader.Read())
{
string username = reader["username"];
string pwd = reader["password"];
}
While you are at it, parameterize your query and prevent sql injection:
SqlCommand cmd = new Sqlcommand("select * from login where username=#username and pwd=#pwd", con);
cmd.Parameters.AddWithValue("#username", txt4name.Text);
cmd.Parameters.AddWithValue("#pwd", txt4pwd.Text);
Definitely heed the advice about SQL injection but here is the answer to your question:
String username;
String pwd;
int columnIndex = reader.GetOrdinal("username");
if (!dataReader.IsDBNull(columnIndex))
{
username = dataReader.GetString(columnIndex);
}
columnIndex = reader.GetOrdinal("pwd");
if (!dataReader.IsDBNull(columnIndex))
{
pwd = dataReader.GetString(columnIndex);
}
string userName = txt4name.Text;
string password = txt4pwd.Text;
Is that really what you want? Just to get that data into variables?
You really need to use parameterized SQL. There's an example here
Furthermore, your question doesn't really make sense; you want the username and password in seperate variables? they already are seperate in your example. If you are unable to assign them to strings I suggest following some tutorials.
Another approach is to load the reader results into a DataTable like so:
DataTable Result = new DataTable();
Result.Load(reader);
If your login table only contains two columns (userName and password) that are unique you end up with Result containing only one row with the information. You can then get the column values from each column:
string userName = Result.Rows[0].Field<string>("userName");
string password = Result.Rows[0].Field<string>("pwd");
private void but_login_Click(object sender, EventArgs e)
{
string cn = "Data Source=.;Initial Catalog=mvrdatabase;Integrated Security=True";
SqlConnection con = new SqlConnection(cn);
con.Open();
SqlCommand cmd = new SqlCommand("select count (*) from logintable where username ='" + txt_uname.Text + "'and password='" + txt_pass.Text + "'", con);
int i = Convert.ToInt32(cmd.ExecuteScalar());
con.Close();
if (i == 1)
{
Form2 f2 = new Form2();
MessageBox.Show("User login successfully........");
this.Hide();
f2.Show();
}
else
{
MessageBox.Show("INCORRECT USERID AND PASSWORD", "Error");
}
}
You can usually find basic usage examples on MSDN, like this one for SqlDataReader.