I am creating a simple app where users create accounts. I want for the user to be able to change their password after making the account.
I am making this in C# using Oledb.
string test = "testing";
con.Open();
OleDbCommand command = new OleDbCommand();
command.Connection = con;
string query = "UPDATE tbl_users SET password = '" + test + "' WHERE username = '" + txtLoginUsername.Text + "'";
MessageBox.Show(query);
command.CommandText = query;
command.ExecuteNonQuery();
con.Close();
I keep getting the error:
" System.Data.OleDbException: 'Syntax error in UPDATE'"
This error is occuring in the line:
command.ExecuteNonQuery();
To clarify what Hossein has answered, when you are building your query command by adding strings together, you are wide-open to SQL-injection. Please read up on it some to protect your future development.
With reference to using "parameters". This is basically referring to a place-holder value for the query, like an "insert here" instead of you hard adding parts to the query like you were wrapping single quotes before and after the values for the password and user name.
Looking at your original query
"UPDATE tbl_users SET password = '" + test + "' WHERE username = '" + txtLoginUsername.Text + "'";
What if someone put in values of
Password: What's Up
Username: O'Conner
Your final query command when concatenated with your approach would create a value
UPDATE tbl_users SET password = 'What's Up' WHERE username = 'O'Conner'
See how the literal values have now screwed-up the string from its intent.
By using the "#" values, this is telling the SQL that hey... there will be another value coming along by the name provided, please use THAT value here. In some databases, they dont use named parameters, but "?" single character instead as a place-holder and you have to add the parameters in the exact order as they appear in the statement you are trying to prepare.
One other thing of personal preference. If your column name is UserName in I would use a parameter name like "#parmUserName" so you know it is EXPLICITLY the parameter and not accidentally just doing UserName = UserName and not get the results. A few more characters, but obvious what its purpose and where coming from works.
Now, how is that applied? Take a look again at Hossein's answer. Notice the two
command.Parameters.AddWithValue("#password", "test");
command.Parameters.AddWithValue("#username", txtLoginUsername.Text);
This is where the parameters are added to the command object. Stating, where you see the #password, use the following value I am putting here, same with #username.
Good luck going forward.
Use this syntax
Use bracket for password in query
because password is reserved word
link List of reserved world
using (var connection = new OleDbConnection("Your Connection String"))
{
var query = "UPDATE tbl_users SET [password] = #password WHERE username = #username";
using (var command = new OleDbCommand(query, connection))
{
connection.Open();
command.Parameters.AddWithValue("#password", "test");
command.Parameters.AddWithValue("#username", txtLoginUsername.Text);
command.ExecuteNonQuery();
}
}
Related
I'm trying to make a login and I keep getting this error:
System.Data.SqlClient.SqlException: 'Incorrect syntax near 'USERNAME'.'
Here is my code
SqlConnection con = new SqlConnection(#"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=C:\Users\Omar\Documents\Data.mdf;Integrated Security=True;Connect Timeout=30");
SqlDataAdapter sda = new SqlDataAdapter("Select Count(*) From [LOGIN] were USERNAME ='" + textBox1.Text +"' and PASSWORD='"+ textBox2.Text +"'",con);
DataTable dt = new DataTable();
sda.Fill(dt);
You're getting voted down not just because this is a duplicate question but because your attempt wraps two security problems in a single piece of code.
So let's take this step by step.
1) Your actual problem is you mispelt WHERE. Your corrected code would look something like
SqlConnection con = new SqlConnection(#"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=C:\Users\Omar\Documents\Data.mdf;Integrated Security=True;Connect Timeout=30");
SqlDataAdapter sda = new SqlDataAdapter("Select Count(*) From [LOGIN] where USERNAME ='" + textBox1.Text +"' and PASSWORD='"+ textBox2.Text +"'",con);
DataTable dt = new DataTable();
sda.Fill(dt);
But you don't need a data adapter or a table, you can return a count from SQL directly. So you could do something like
string sql = "select count(*) from users where username = '" + username + "' and password = '" + password + "'";
using (SqlConnection conn = new SqlConnection(connStr))
{
conn.Open();
using (SqlCommand command = new SqlCommand(query, conn))
{
int result = (int)command.ExecuteScalar();
if (result > 0)
{
/// login sucessful
}
}
}
This would work, but you have a security vulnerability called SQL injection.
If we look at a correct login your SQL string would be
select count(*) from login where username = 'alice' and password = 'bob'
This works fine, but if I enter the classic example of SQL injection for a login page as the password, ' OR 1=1 -- then your SQL string becomes this;
select count(*) from login where username = 'alice' and password = '' OR 1=1 --'
This line of SQL will always return 1, because it's highjacked the SQL via SQL injection, adding an OR clause at the end of the statement, OR 1=1 which is always going to be true. It then uses SQL comment syntax to comment out whatever comes after it. So now I can login as anyone at all, even usernames that don't exist.
2) The correct way to build SQL strings, if you don't want to use ORMs that do this for you (and really, use an ORM, all the protection is automatic) is to use a parameterized query, which takes the input and formats it in such a way that any special characters aren't taken as SQL commands, like so
string sql = "select count(*) from login where username = #username and password = #password";
using (SqlConnection conn = new SqlConnection(connStr))
{
conn.Open();
using (SqlCommand command = new SqlCommand(query, conn))
{
command.Parameters.Add(new SqlParameter("#username", username));
command.Parameters.Add(new SqlParameter("#password", password));
int result = (int)command.ExecuteScalar();
if (result > 0)
{
/// login sucessful
}
}
}
The parameters are in the SQL query as #parameterName, and then added with command.Parameters.Add(). Now you've avoid SQL injection
3) However this still a security problem. You're storing your passwords in plaintext. If I can gain access to your SQL database (via SQL injection, or you leaving the server open to the world) once I have a copy of the database I have your usernames and passwords and your company is going to end up on haveibeenpwned. You shouldn't be doing this. Passwords should be protected, not via encryption, but via what is called hashing and salting. This transforms the passwords into a value that is derived from it via a one way function, it takes the password, feeds it into some math, and the result out the other side represents the password, but you can't go back the other way, you can't figure out the password from the salted hash. Then when you compare logins, you compute the hash again, and use that in your comparison, in an ORM driven query or a parameterised query.
Now, with all that in mind, I'd strongly advise you to avoid doing any of this yourself. C# & ASP.NET have libraries for usernames and passwords in ASP.NET Identity. I would much rather see you use that, not just because I happen to be the PM owner for that and for .NET Security as a whole, but because it does everything right for you, without you having to do any work.
If this is for a real world application please take some time to go through the OWASP project, it has lots of examples of security problems and details on how to fix them.
Please...
learn about parameters; the code you have is open to SQL injection, which is a huge problem (especially, but not just, on a login form)
learn about not storing plain-text passwords, instead using salted cryptographic hashes
learn about IDisposable; multiple of the objects involved here are disposable and need using
don't use DataTable unless you know why you're using it - there is no reason whatsoever to use it here
learn about tools that will help do all of the above for you
and when, and only when, you have the above "down": fix the typo
Here's a version using "dapper", that covers most of this:
using (var con = SqlConnection(#"...not shown..."))
{
var hash = HashPasswordUsingUsernameAsSalt(
textBox1.Text, textBox2.Text); // impl not shown
int count = con.QuerySingle<int>(#"
select COUNT(1) from [LOGIN]
where [USERNAME]=#cn and [PW_HASH]=#hash",
new { cn = textBox1.Text, hash });
// TODO: do something with count
}
Look like on your 2nd line you have a typo for the WHERE clause.
SqlDataAdapter sda = new SqlDataAdapter("Select Count(*) From [LOGIN] WHERE USERNAME ='" + textBox1.Text +"' and PASSWORD='"+ textBox2.Text +"'",con);
However, you need to learn about SQL injection attacks since your SQL is wide open to hack attempts.
Ok, so to update. I have spoken to my professor who said that worrying about encrypted passwords/sql injection etc will wait until next term. For now, I should concentrate on the basics (no login granted if any (or both) fields are left empty, no user can login with their password but another users username etc.) I have now condensed my query into one, to check for username and password together, this prevents a login using a combination of one users password and anothers username or vice versa.
The code also won't log in if either one or both fields are left empty. My issue now is that my script alerts aren't popping up correctly. If both fields are left empty, it won't log in but it also won't have the script alert message pop-up. Same with a successful login, it will take you to the next page but won't popup with the welcome message. Can anyone tell me why? I have updated my code here to show how it looks now. Thanks!
protected void loginButton_Click(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(userText.Text) || string.IsNullOrEmpty(passText.Text)) return;
{
Response.Write("<script>alert('Details are incorrect, please try again');</script>");
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["newregDBConnectionString"].ConnectionString);
conn.Open();
var checkUser = "select count(*) from parent " +
"where parentID='" + userText.Text + "' " +
"and password='" + passText.Text + "' ";
SqlCommand com = new SqlCommand(checkUser, conn);
int temp = Convert.ToInt32(com.ExecuteScalar().ToString());
conn.Close();
if (temp == 1)
{
conn.Open();
string checkPassword = "select password from parent where password='" + passText.Text + "'";
SqlCommand passCom = new SqlCommand(checkPassword, conn);
var obj = passCom.ExecuteScalar();
string password = obj?.ToString().Trim();
if (password == passText.Text)
{
Session["New"] = userText.Text;
Response.Write("<script>alert('Details are correct, welcome');</script>");
Response.Redirect("Payment.aspx");
}
else
{
Response.Write("<script>alert('Details are incorrect, please try again');</script>");
userText.Text = "";
passText.Text = "";
}
}
else
{
Response.Write("<script>alert('Details are incorrect, please try again');</script>");
userText.Text = "";
passText.Text = "";
}
conn.Close();
}
}
}
}
On the second query you only check passwords, not the username. So if there is anybody with an empty password, then everybody is let in with an empty password.
Doing two queries is not needed, it simply is better to do it all in one go:
var sql = "select count(*) from parent " +
"where parentID='" + userText.Text + "' " +
"and password='" + passText.Text + "' ";
There are several other things to improve, e.g.:
What if either text contains a single quote...(answer: the query throws an error, or worse you get SQL injection problems)
What if hackers manage to copy your database...(answer: then they know ALL passwords, because there is no hashing being done)
But I guess that is for a later moment / different question.
string password = obj?.ToString().Trim();
If obj is null, then the above expression will result in an empty string. Therefore when you:
if (password == passText.Text)
The above will succeed when passText.Text is also an empty string.
As an aside, you really should not be storing a plain text password either.
Maybe just check at the beginning ? :
protected void loginButton_Click(object sender, EventArgs e)
{
if ( string.IsNullOrEmpty(userText.Text) || string.IsNullOrEmpty(passText.Text)) return;
// rest of the code ...
}
Aside from the above, you should make use of the SqlCommand object and use SqlParameter for safety.
instead of yours :
string checkUser = "select count(*) from parent where parentID='" + userText.Text + "'";
SqlCommand com = new SqlCommand(checkUser, conn);
you can do :
string checkUser = "select count(*) from parent where parentId=#userName";
SqlParameter param = new SqlParameter("#userName", userText.Text);
SqlCommand com = new SqlCommand(checkUser, conn);
com.Parameters.Add(param);
Sidenote :
To get rid of the problems #Sefe pointed out you can just check both ( password and username ) in one query :
string checkUser = "select [enter_some_column_name_here] from parent where parentId=#userName and password=#userPass";
SqlParameter paramUsername = new SqlParameter("#userName", userText.Text);
SqlParameter paramPassword = new SqlParameter("#userPass", passText.Text);
SqlCommand com = new SqlCommand(checkUser, conn);
com.Parameters.Add(paramUsername);
com.Parameters.Add(paramPassword);
But that's still not enough. You're not encrypting user password in database and you're trying to compare raw user password. To fix this you should encrypt passwords before entering them into database and then compare encrypted versions of passwords :
byte[] buffer = Encoding.UTF8.GetByes(passText.Text);
SqlParameter paramPassword = null;
using ( SHA512 sha= new SHA512Managed())
{
byte[] hash = sha.ComputeHash(buffer);
StringBuilder builder= new StringBuilder();
for (int i = 0; i < hash.Length; i++)
{
builder.Append(hash[i].ToString("x2"));
}
paramPassword = new SqlParameter("#userPass", builder.ToString());
}
So being aware of encryption problem you should change this line :SqlParameter paramPassword = new SqlParameter("#userPass", passText.Text); into above piece of code.
I dont think you need two queries for this. You can do the same in just one:
Disclaimer: This code is unsafe and it just pretends to answer a specific question. Dont manage authentication like this.
"select count(*) from parent where parentID='" + userText.Text + "' and password='" + passText.Text + "'"
If this query returns 1 the user could be authenticated.
Annother tips you should consider to improve your code:
SqlConnection implements IDisposable, wich means it can release for you unused resources when no longer needed by enclosing it in a using statement. This forces the connection to automatically close, even if an exception occurs. You can see examples here:
https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlconnection(v=vs.110).aspx
I don't know what are the security requirements for this application, but appart from the sql injection problem, it is not generally a good idea to store plain-text user passwords in a database. You should consider using an authentication framework to manage these problems for you, like ASP net Membership:
https://msdn.microsoft.com/en-us/library/tw292whz.aspx
I hope this helps. Cheers!
You are not checking for a specific username/password combination. You are checking first if a user with a username exists:
string checkUser = "select count(*) from parent where parentID='" + userText.Text + "'";
SqlCommand com = new SqlCommand(checkUser, conn);
And then you are checking if any user with a specifc password exists:
string checkPassword = "select password from parent where password='" + passText.Text + "'";
SqlCommand passCom = new SqlCommand(checkPassword, conn);
So you just need any user without a username and any (other or the same) user without a password in the DB. Also, anyone can create a user account and use his password to log in as any other user.
You need to query for a combination of both, username and password.
There are two other dangerous issues in your code:
Never store passwords directly in your DB.
Never, ever, use the text of your text boxes directly in your SQL query.
This combination will make it ridiculously easy for even a newbie hacker to log in without requiring a password (or do even worse with your DB).
Maybe you should check both, username and password at same query
select count(*) from parent where parentID='" + userText.Text + "' AND password='" + passText.Text + "'"
This question already has answers here:
SQL Server Invalid column name when adding string value
(5 answers)
Closed 6 years ago.
Error is showing that invalid column name mustufain.
mustufain is the value of UserName.Text.toString()
string query = "select userid from register where username = " + UserName.Text.ToString() + " and " + "password = " + Password.Text.ToString();
SqlCommand cmd1 = new SqlCommand(query,connection);
connection.Open();
SqlDataReader rd1 = cmd1.ExecuteReader();
while(rd1.Read())
{
Session["checkuserid"] = rd1["userid"];
}
connection.Close();
Firstly, you should not be using string concatenation to build your queries as it can leave you vulnerable to things like SQL Injection attacks and it can cause issues with your queries being incorrect (as you are missing tick marks around your parameters) :
// This would attempt to state username = mustufain instead of
// username = 'mustufain' (and SQL doesn't know what mustufain is)
var query = "select userid from register where username = '" + UserName.Text + "' and " + "password = '" + Password.Text + "'";
A better approach using parameterization would look like the following, which avoids the incorrect syntax and offers you protection against any nasty injections :
// Open your connection
using(var connection = new SqlConnection("{your connection string}"))
{
// Build your query
var query = "SELECT TOP 1 userid FROM register WHERE username = #username AND password = #password";
// Build a command (to execute your query)
using(var command = new SqlCommand(query, connection))
{
// Open your connection
connection.Open();
// Add your parameters
command.Parameters.AddWithValue("#username",UserName.Text);
command.Parameters.AddWithValue("#password",Password.Text);
// Execute your query
var user = Convert.ToString(command.ExecuteScalar());
// If a user was found, then set it
if(!String.IsNullOrEmpty(user))
{
Session["checkuserid"] = user;
}
else
{
// No user was found, consider alerting the user
}
}
}
Finally, you may want to reconsider how you are storing your credentials (in clear text). ASP.NET offers a wide variety of providers that can help handle this process for you so that you don't have to do it yourself.
You are trying to concatenate strings to build an sql query and, as usual, you get errors. In your specific case you forget to enclose your string values between single quotes. But the only correct way to do this query is by the way of a parameterized query
string query = #"select userid from register
where username = #name and password = #pwd";
using(SqlCommand cmd1 = new SqlCommand(query,connection))
{
connection.Open();
cmd1.Parameters.Add("#name", SqlDbType.NVarChar).Value = UserName.Text;
cmd1.Parameters.Add("#pwd", SqlDbType.NVarChar).Value = Password.Text;
using(SqlDataReader rd1 = cmd1.ExecuteReader())
{
....
}
}
Notice also that storing passwords in clear text in your database is a very bad practice and a strong security risk. On this site there are numerous questions and answers that explain how to create an hash of your password and store that hash instead of the clear text
For example: Best way to store passwords in a database
I'm working on a C# project with some data bases. I'm getting an error when executing the following function:
//Returns true if the username and password are correct. Otherwise it returns false.
public bool LogInto(string name, string pass, OleDbConnection cnx)
{
DataTable res = new DataTable();
OleDbDataAdapter adp = new OleDbDataAdapter("SELECT User,Password FROM UserPassword WHERE (User='"+name+"' AND Password='"+pass+"')", cnx);
adp.Fill(res);
bool found = false;
String user = Convert.ToString(res.Rows[0]["User"]);
String password = Convert.ToString(res.Rows[0]["Password"]);
if (name==user && pass==password)
found = true;
return found;
}
So this is the full function, however I'm getting an error, I just replaced && with AND. But it still doesn't work. I'm getting ("There was an error parsing the query. // Token number, token line offset, token in error.
What's wrong with it? I had the same function but instead of taking just one row from the data table, it took the whole table and with a loop it looked the row we were looking for. However, I'm trying to do this one, just taking the row we need, because it is more efficient.
Could you guys help me? I can't find my mistake.
Thank you so much
You have some issues with the query:
The and operator in SQL is and, not &&
The query is WIDE OPEN FOR SQL INJECTION ATTACKS. You have to escape the strings to be correctly interpreted as string literals.
You can do it like this:
string query =
"SELECT User, Password FROM UserPassword WHERE Username = '" +
name.Replace("\\", "\\\\").Replace("'", "\\'") +
"' and Password = '" +
pass.Replace("\\", "\\\\").Replace("'", "\\'") +
"'";
Note: This way to escape the strings is specific to MySQL. Each database have a different set of characters that needs to be escaped, and in different ways.
If possible you should use a parameterised query instead of concatenating string into the query. That makes it easier to get it correct.
First please use parameterized one like this, with IDisposable inherited
using(SqlCommand cmd = new SqlCommand())
{
cmd.CommandType = CommandType.Text;
cmd.CommandText = #""SELECT up.User, up.Password FROM dbo.UserPassword up WHERE up.Username = #Param1" AND Password = #Param2;
cmd.Parameters.Add("#Param1", SqlDbType.Varchar).Value = 'ABC';
.............
}
second try to encrypt it or hash it, there are lot of information about hashing and encrytion on web
I have used the standard user tables that ASP.net setup and I'm looking to be able to delete users. To do this first off I need to delete the user id from a table called memberships and then delete the user. To do this I have 2 text boxes setup one for user id and other for user name.
Any ideas of a T-SQL statement that will delete the membership user id first and then move onto the delete username this is my statement so far
else
{
try
{
connection.Open();
cmd = new SqlCommand("DELETE from Membershio
WHERE UserId ='" + deleteuserIDbox.Text + "'", connection);
cmd = new SqlCommand("DELETE from Users WHERE UserName ='" + deleteuserbox.Text + "'", connection);
cmd.ExecuteNonQuery();
update.Text = "Your data has been removed";
}
catch
{
update.Text = "Your data has not been deleted";
}
}
The two tables are related hence I need to delete the user id first and then the username
any help greatly appricated
If understand it right, your input method has serious issues.
For example,
UserID UserName
1 testUser
2 testUser2
With the logic in your application; I can enter "1" into deleteuserIDbox and "testUser2" into deleteuserbox which in turn would remove userID 1 but not username "testUser".
If you didn't do it already, you need to associate those two tables using Foreign Key on UserID. So the linkage is persisted with UserID field.
Another issue is, you are directly executing the query with the input from user thus enabling the possiblity of sql injection.
About your query, you can put " cmd.ExecuteNonQuery();" between your two cmd statements.
To use your current code, you will need to execute the first query, then set the CommandText for the second query and execute that.
using (SqlCommand cmd = connection.CreateCommand())
{
cmd.CommandText = "DELETE FROM Membership WHERE UserID = #UserID";
cmd.Parameters.AddWithValue("#UserID", deleteuserIDbox.Text);
connection.Open();
cmd.ExecuteNonQuery();
cmd.Paramters.Clear();
cmd.CommandText = "DELETE from Users WHERE UserName = #UserName";
cmd.Parameters.AddWithValue("#UserName", deleteuserbox.Text);
cmd.ExecuteNonQuery();
}
Another option is to use a stored procedure that would allow you to run the two queries together.
Another option is to do cascading deletes. Here is a link on how to accomplish that.
Lastly, you are opening yourself up to SQL Injection. You should NEVER take input from a user and concatenate that data into a SQL statement. You should either use a Stored Procedure or a parameterized query(like I used above).
You're not executing the first command:
connection.Open();
cmd = new SqlCommand("DELETE from Membershio
WHERE UserId ='" +
deleteuserIDbox.Text + "'", connection);
cmd.ExecuteNonQuery();
cmd = new SqlCommand("DELETE from Users WHERE
UserName ='" + deleteuserbox.Text +
"'", connection);
cmd.ExecuteNonQuery();
Also, these commands should be executed in a transaction.
A bit late but I only noticed your question today.
By doing this on the database you are bypassing all the good stuff! You should do this in C# by calling the Membership::DeleteUser Method
http://msdn.microsoft.com/en-us/library/5xxz7y3a.aspx
You should not mess with the internals of the Membership system at all.