How can I improve my code? [closed] - c#

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");

Related

How can i pass a value to a label from a database based on the users details

I have a login table with each user having different roles eg Staff, Admin.
I can have the user log in sucessfully with their username displaying between pages on the console application.
I am trying to Add in a new label beside the username label so upon login the next page will have something like this Admin: Johny or Staff: Bob
What i have tried to do is Change the query to:
"SELECT Role From User_Table WHERE eb_number='" + usernametxt.Text + "' and Password = '" + textBox1.Text + "'",con);
but this does not work either.
private void loginbtn_Click(object sender, EventArgs e)
{
//GRANT ACCESS TO THE DATABASE WITH USERNAME AND PASSWORD WHICH IS STORED IN THE DATABASE.
SqlConnection con = new SqlConnection(conString);
con.Open();
if (con.State==System.Data.ConnectionState.Open)
{
SqlDataAdapter sda = new SqlDataAdapter("SELECT Count(*) From User_Table WHERE eb_number='" + usernametxt.Text + "' and Password = '" + textBox1.Text + "'",con);
DataTable dt = new DataTable();
sda.Fill(dt);
if (dt.Rows[0][0].ToString() == "1")
{
this.Hide();
Main ss = new Main(usernametxt.Text); //usernametxt is passed in to prevent error
ss.Show();
MessageBox.Show("Logged in sucessfully");
}
else
{
MessageBox.Show("Incorrect Username/Password Combination. Try Again");
}
}
}
Main.cs
public Main(string Username/*, string Role*/) //passing username values
{
InitializeComponent();
Username_lbl.Text = Username; //Displaying username
//Main_Role_lbl.Text = Role;
At he minute my code Just lets me log in and out reading the username and passwords. I am unsure if i can add in to search for the Role for the username in the SQL query this way? What i expected it the code to do was have a login like Admin: Johny or Staff: Bob
Here you go something similar to your implementation:
private void loginbtn_Click(object sender, EventArgs e)
{
var conString = "ReplaceWithMyConnectionString";
string userRole = null;
using (var con = new SqlConnection(conString))
{
con.Open();
var cm = con.CreateCommand();
cm.CommandType = System.Data.CommandType.Text;
cm.CommandText = "SELECT TOP 1 Role FROM User_Table WHERE eb_number = #eb_number AND and Password = #Password";
cm.Parameters.Add(new SqlParameter("#eb_number", System.Data.SqlDbType.VarChar, 50) { Value = usernametxt.Text });
cm.Parameters.Add(new SqlParameter("#Password", System.Data.SqlDbType.VarChar, 50) { Value = textBox1.Text });
using (var reader = cm.ExecuteReader(System.Data.CommandBehavior.SingleRow))
{
if (reader.Read())
{
userRole = reader["Role"].ToString();
}
}
}
if (userRole != null)
{
this.Hide();
Main ss = new Main(usernametxt.Text, userRole); //usernametxt is passed in to prevent error
ss.Show();
MessageBox.Show("Logged in sucessfully");
}
else
{
MessageBox.Show("Incorrect Username/Password Combination. Try Again");
}
}
There are a few things that are different, I'll explain the reason behind them:
I replaced with parameters the string concatenation you were doing on your SQL. This is to avoid SQL injection. Have you wondered
what would happen if the user enters the character ' in the
username or password textboxes? there's more to this, please research this subject.
I'm instantiating your connection inside a using statement. This will make sure that your connection is closed (disposed) when we are done with the db stuff.
Replaced the DataAdapter/DataTable with a leaner SqlCommand/SqlDataReader classes.
I separated the logic in a way that the connection can be closed asap, and is not being interrupted by the call to MessageBox.Show().
Also, and very important, never store your passwords as clear text in the database, please do some research about hashing functions and why they should be used in this context.
I hope this helps.

Trying to update hashed password c#

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

Syntax error in UPDATE statement in ASP.NET using C# with Access Database

I'm getting a "Syntax error in UPDATE statement" error when I run the following Access statements. How do I get past that?
This is the relevant portion of my web page code.
protected void Button1_Click(object sender, EventArgs e)
{
string connect = "Provider=Microsoft.Jet.OleDb.4.0;Data Source=C:\\Users\\Prasat PVS\\Documents\\db.mdb";
string q1 = "SELECT * FROM users WHERE password ='" + TextBox1.Text + "'";
string q2 = "UPDATE users SET password='"+TextBox2.Text+"' WHERE password='"+TextBox1.Text+"'";
using (OleDbConnection con = new OleDbConnection(connect))
{
con.Open();
using (OleDbCommand cmd = new OleDbCommand(q1, con))
{
OleDbDataReader dr = cmd.ExecuteReader();
if (dr.Read())
{
using (OleDbConnection con1 = new OleDbConnection(connect))
{
con1.Open();
using (OleDbCommand cmd1 = new OleDbCommand(q2, con1))
{
cmd1.ExecuteNonQuery();
}
Label1.Text = "Your Password Has Been Changed Successfully";
con1.Close();
con.Close();
}
}
else
{
Label1.Text = "Your Password Is Incorrect Try Again";
}
}
}
}
maybe the problem is because you have used password as name for password field... instead use pass or something other
My bet is that your password has an apostrophe in it. If that's the case, you'll have something like UPDATE users SET password = 'pass'word'... which is pretty clearly the wrong syntax. That's the most likely thing I can see that could be causing an error like that.
Yet another point to parameterizing your queries...
And while you're at it, I mentioned this in a comment, but you'd be much better to only run one query (your update, after you add in a check for the username) and check the result of ExecuteNonQuery to know whether any rows were affected (the password changed successfully) or not (the username or password was incorrect).

Hash encrypting password when inserting into database

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

How can I get a username and password from my database in C#?

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.

Categories