I have created the following WebMethod in the back end of my application where the users login through the front end.
[WebMethod]
public String Login(String userName, String password)
{
OleDbConnection connect = new OleDbConnection(connection);
connect.Open();
OleDbCommand command = new OleDbCommand("Select * from login where userName='" + userName + "' and password ='" + password + "'", connect);
command.CommandType = CommandType.Text;
OleDbDataAdapter adapter = new OleDbDataAdapter();
adapter.SelectCommand = command;
DataSet NSNSet = new DataSet();
adapter.Fill(NSNSet);
string username = NSNSet.Tables[0].Rows[0]["firstName"].ToString() + NSNSet.Tables[0].Rows[0]["lastName"].ToString();
int userID = System.Convert.ToInt16(NSNSet.Tables[0].Rows[0]["UID"].ToString());
return username + "," + userID;
}
Currently, I have error handling in place which states -
catch(Exception ex)
{
string error = System.Convert.ToString(ex);
if (error.Contains("There is no row at position 0"))
{
status.Text = "Incorrect Username/Password combination";
}
}
This works fine, however how could I aulter my code so that it brings back a more specific error, i.e. states if the userName or password specifically are incorrect?
Don't give out to much details, just give a simple login error message, but don't say that username is incorrect or password is incorrect, cause a hacker can use that information
a simple text saying login unsuccessful should be ok
You should do like this:
public String Login(String userName, String password)
{
OleDbConnection connect = new OleDbConnection(connection);
connect.Open();
OleDbCommand command = new OleDbCommand("Select UID, firstName, lastName from login where userName=? and password =?", connect);
command.CommandType = CommandType.Text;
//to avoid sql injection
command.Parameters.Add(userName);
command.Parameters.Add(password);
OleDbDataAdapter adapter = new OleDbDataAdapter();
adapter.SelectCommand = command;
DataSet NSNSet = new DataSet();
adapter.Fill(NSNSet);
if (NSNSet.Tables[0].Rows.Count == 0)
return "Access denied";
string username = NSNSet.Tables[0].Rows[0]["firstName"].ToString() + NSNSet.Tables[0].Rows[0]["lastName"].ToString();
int userID = int.Parse(NSNSet.Tables[0].Rows[0]["UID"].ToString());
return username + "," + userID;
}
Or a better way, using DataReader for performance:
public String Login(String userName, String password)
{
OleDbConnection connect = new OleDbConnection(connection);
connect.Open();
OleDbCommand command = new OleDbCommand("Select UID, firstName, lastName from login where userName=? and password =?", connect);
command.CommandType = CommandType.Text;
//to avoid sql injection
command.Parameters.Add(userName);
command.Parameters.Add(password);
OleDbDataReader reader=command.ExecuteReader();
if (reader.Read())
{
//that means there's at least one row
string username = reader["firstName"] + " " + reader["lastName"];
int userID = int.Parse(reader["UID"].ToString());
return username + "," + userID;
}
else
{
//no combination username-password found
return "Access denied";
}
}
First, this code is open to SQL injection. Second, if you want to know specifically which element is incorrect, you have to break down your query into two components (ie. query username and password separately)
You can change you select query a little bit to this:
"select * from login where userName='"+userName+"'";
if there is no row in DataSet then write
Invalid UserName
and if user exist then check if password match or not if not match then write
Invalid Password
Related
I'm trying to store hashed passwords in db. Here is my code:
string passwords = textBox2.Text;
string salt = BCrypt.Net.BCrypt.GenerateSalt(12);
string hashPwd = BCrypt.Net.BCrypt.HashPassword(passwords, salt);
try
{
SQLiteCommand command = new SQLiteCommand();
connection.Open();
command.Connection = connection;
command.CommandText = ((#"INSERT INTO acc (UserName, Pass) VALUES ('" + textBox1.Text + "','" + hashPwd+ "');"));
command.ExecuteNonQuery();
connection.Close();
}
catch (Exception ex)
{
MessageBox.Show("Error:" + ex.ToString());
return;
}
Login/verification code:
try
{
SQLiteDataAdapter sqlad = new SQLiteDataAdapter("SELECT COUNT(*) From acc WHERE Username = '" + textBox1.Text + "' AND Pass = '" + textBox2.Text + "' ", connection);
DataTable dt = new DataTable();
sqlad.Fill(dt);`
string userid = dt.Rows[0]["UserName"].ToString();
string password = dt.Rows[0]["Pass"].ToString();
bool flag = BCrypt.Net.BCrypt.Verify(textBox2.Text, password);
if (userid == textBox1.Text && flag == true)
{
Form2 frm = new Form2();
frm.Show();
}
else
{
MessageBox.Show("Invalid UserId or password");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
return;
}
I can't verify Password, I'm getting error, could you help me please? One more question, should I save salt too in database?
There are a couple of problems with your code:
1. SQL Injection
Both your insert and verification code blocks are vulnerable to SQL injection, since they allow text you take directly from user input into the SQL string executed, a vulnerability they can use to either subvert the login check, or destroy your database. Don't do it!
2. Your selection of the hashed password back from the database does not select the hashed password.. or anything of interest.
Consider what you have here:
SQLiteDataAdapter sqlad = new SQLiteDataAdapter(#"
SELECT
COUNT(*)
From
acc
WHERE
Username = '" + textBox1.Text + "'
AND
Pass = '" + textBox2.Text + "' ", connection);
So, let's say I gave my username as "Steve" and password as "hello", which got hashed to "ab123cdef", and inserted to your acc table as:
UserName Pass
Steve ab123cdef
And when I come to verify this with the original correct user and password, your select statement says "give me the number of rows with username 'Steve' and pass 'hello'", which will duly return zero.
Your code should throw an exception here:
string userid = dt.Rows[0]["UserName"].ToString();
Since the result set doesn't contain the username as an output.
Here is a basic little example using the libraries you've chosen to show how you could insert and verify a password successfully.
Regarding what to do with the salt, the function HashPassword has prepended the salt to the password hash, so if you store the output of this, you are storing the salt. The verify function you use in verification will handle and check this for you.
static void CreateUser(string username, string password)
{
if (UserExists(username))
throw new InvalidOperationException("User already exists");
string salt = BCrypt.Net.BCrypt.GenerateSalt(12);
// if you look at the hashed password, notice that it's prepended with the salt generated above
string hashedPassword = BCrypt.Net.BCrypt.HashPassword(password, salt);
using (SQLiteConnection connection = new SQLiteConnection(connectionString))
{
connection.Open();
SQLiteCommand insertCommand = new SQLiteCommand(connection);
insertCommand.CommandText = #"INSERT INTO acc (UserName, Pass) VALUES (#username, #hashedPass);";
// use parameterised queries to mitigate sql injection
insertCommand.Parameters.Add(new SQLiteParameter("#username", username));
insertCommand.Parameters.Add(new SQLiteParameter("#hashedPass", hashedPassword));
insertCommand.ExecuteNonQuery();
}
}
To verify a given username/password, all we need back from the database is the output of the hash function to verify against what we've been given.
static bool Verify(string username, string password)
{
using (SQLiteConnection connection = new SQLiteConnection(connectionString))
{
connection.Open();
SQLiteCommand checkUserCommand = new SQLiteCommand(connection)
{
CommandText = #"SELECT Pass FROM acc WHERE UserName = #username;"
};
checkUserCommand.Parameters.Add(new SQLiteParameter("#username", username));
var hashedPassword = (string)checkUserCommand.ExecuteScalar();
return BCrypt.Net.BCrypt.Verify(password, hashedPassword);
}
}
Usage would be something like..
if (!UserExists(username))
{
CreateUser(username, password);
Console.WriteLine("User {0} created", username);
}
else
{
bool loginOk = Verify(username, password);
Console.WriteLine("Login ok?: {0}", loginOk);
}
I have one table called Users, which have 4 columns
UserId
UserName
Password
Role
If login is successful, I want to know the UserId and Role values ,
for login validate I wrote following function,
private bool ValidationFunction(string username, string pwd)
{
bool boolReturnValue = false;
string s = "correct connection string";
SqlConnection con = new SqlConnection(s);
con.Open();
string sqlUserName;
sqlUserName = "SELECT UserName,Password FROM Users WHERE UserName ='" + username + "' AND Password ='" + pwd + "'";
SqlCommand cmd = new SqlCommand(sqlUserName, con);
string CurrentName;
CurrentName = (string)cmd.ExecuteScalar();
if (CurrentName != null)
{
boolReturnValue = true;
}
else
{
Session["UserName"] = "";
boolReturnValue = false;
}
return boolReturnValue;
}
ExecuteScalar() function returns only the top record value of the first column. So you need to use ExecuteReader() instead.
Other important thing is you better use a parameterised query to pass those user typed values into the database. You are open for sql injection attacks this way.
Try this:
using (SqlConnection cnn = new SqlConnection("yourConnectionString"))
{
string sql= "select userId,role from users " +
"where username=#uName and password=#pWord";
using (SqlCommand cmd = new SqlCommand(sql,cnn))
{
cmd.Parameters.AddWithValue("#uName", username);
cmd.Parameters.AddWithValue("#pWord", pwd);
cnn.Open();
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
//get the reader values here.
}
}
}
If UserID and Role are in the Users table, you can use the code below. It has the added benefit of protection from SQL injection attacks using parameters.
private class User
{
public int UserID {get;set;}
public string Role {get;set;}
public string UserName {get;set;}
}
private bool ValidationFunction(string username, string pwd, out User)
{
bool boolReturnValue = false;
string s = "correct connection string";
SqlConnection con = new SqlConnection(s);
con.Open();
string sqlUserName;
sqlUserName = "SELECT UserName,Password,UserID,Role FROM Users WHERE UserName =#usr AND Password=#pwd";
SqlCommand cmd = new SqlCommand(sqlUserName, con);
cmd.Parameters.Add(new SqlParameter("usr", username));
cmd.Parameters.Add(new SqlParameter("pwd", pwd));
SqlDataReader reader = command.ExecuteReader();
if (reader.Read())
{
boolReturnValue = true;
User = new User(){UserName = username, UserID=reader.GetInt32(2), Role=reader.GetString(3)};
}
else
{
Session["UserName"] = "";
boolReturnValue = false;
}
return boolReturnValue;
}
Use query
SqlDataReaer reader= Select *from Users where password="yourPassword"
and then you can get whatever you want i.e. reader["userName"] etc
con.Open();
string mysql; // generate an sql insert query for the database
mysql = "SELECT 1 FROM [Users] WHERE Username=? AND Password=?";
OleDbCommand cmd = new OleDbCommand(mysql, con);
cmd.Parameters.AddWithValue("#p1", tbUser.Text);
cmd.Parameters.AddWithValue("#p2", tbPass.Text);
cmd.ExecuteNonQuery();
int temp = Convert.ToInt32(cmd.ExecuteScalar().ToString());
if(temp==1)
{
Session["LogIn"] = lblUser.Text;
lblLogin.Text = "Welcome " + lblUser.Text + ", you are now logged in.";
}
else
{
lblLogin.Text = "Invalid Username/Password!";
}
con.Close();
Error: Syntax error in FROM clause.
"OleDbException was unhandled by user code."
Thanks.
EDIT
Now that I look closer there are many things wrong with this code. Standard practice is to check for the username/password combination in one shot:
mysql = "SELECT 1 FROM [User] WHERE UserName=? AND Password=?";
OleDbCommand CheckUser = new OleDbCommand(mysql, con);
// Add OleDbParameters here with the correct type/length
CheckUser.Parameters.Add("#userName", OleDbType.Char, 20).Value = tbUser.Text ;
CheckUser.Parameters.Add("#password", OleDbType.Char, 20).Value = tbPass.Text ;
int temp = Convert.ToInt32(CheckUser.ExecuteScalar().ToString());
and adding parameters to the command with the username and password values. That way hackers can't determine valid usernames without knowing the password.
This block:
mysql2 = "SELECT * FROM [User] WHERE Password='" + tbPass.Text + "'";
OleDbCommand Pass = new OleDbCommand(mysql2, con);
string Password = Pass.ExecuteScalar().ToString();
Will return the first column form the first row of the result set. Unless Password is the first column in the User table, you're not getting the password back, you're getting some other value.
It could be:
mysql2 = "SELECT password FROM [User] WHERE Password='" + tbPass.Text + "'";
OleDbCommand Pass = new OleDbCommand(mysql2, con);
string Password = Pass.ExecuteScalar().ToString();
First, just because it builds doesn't mean it's right.
Second, your code is vulnerable to SQL injection.
Third, without an error message or intent there's no way for us to divine what's wrong.
Last but not least: your code will only work if the first row of the first column obtained with the query returns a value of 1. I don't know what you're doing but if all else works for you, you may want to check that.
You can simply do it as :
con.Open();
string mysql; // generate an sql insert query for the database
mysql = "SELECT 1 FROM [Users] UserName='" + tbUser.Text + "' AND
Password='"+ tbPass.Text+"'";
OleDbCommand CheckUser = new OleDbCommand(mysql, con);
int temp = Convert.ToInt32(CheckUser.ExecuteScalar());
if(temp==1)
{
//Login
}
else
{
//Invalid UserName or Password.
}
I'm trying to do a Login code in C# with MySQL. Basically the user enters a username and password then the code checks the database if the the password is correct. I'm having trouble getting the code to read from the data base... Here is where I'm at.
public string strUsername;
public string strPassword;
//Connect to DataBase
MySQLServer.Open();
//Check Login
MySqlDataReader mySQLReader = null;
MySqlCommand mySQLCommand = MySQLServer.CreateCommand();
mySQLCommand.CommandText = ("SELECT * FROM user_accounts WHERE username =" +strUsername);
mySQLReader = mySQLCommand.ExecuteReader();
while (mySQLReader.Read())
{
string TruePass = mySQLReader.GetString(1);
if (strPassword == TruePass)
{
blnCorrect = true;
//Get Player Data
}
}
MySQLServer.Close();
From what I've done in the past, I thought this would work but if I print it, it Seems like its not being read. I am still fairly new to MySQL so any help would be Great.
Non-numeric field value must be enclosed with single quote.
mySQLCommand.CommandText = "SELECT * FROM user_accounts WHERE username ='" +strUsername + "'";
mySQLCommand.Connection=MySQLServer;
but you have to use Parameters to prevent SQL Injection.
mySQLCommand.CommandText = "SELECT * FROM user_accounts WHERE username =#username";
mySQLCommand.Connection=MySQLServer;
mySQLCommand.Parameters.AddWithValue("#username",strUsername);
string con_string = #"Data Source=.\SQLEXPRESS;AttachDbFilename=C:\Database.mdf;Integrated Security=True;User Instance=True";
string query = "SELECT * FROM Users WHERE UseName='" + txtUserName.Text.ToString() + "' AND Password='" + txtPassword.Text + "'";
SqlConnection Con = new SqlConnection(con_string);
SqlCommand Com = new SqlCommand(query, Con);
Con.Open();
SqlDataReader Reader;
Reader = Com.ExecuteReader();
if (Reader.Read())
{
lblStatus.Text="Successfully Login";
}
else
{
lblStatus.Text="UserName or Password error";
}
Con.Close();
As AVD said you should use parameters to prevent sql injection....
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.