I am trying to create a login page where you would enter in a username and a password. It will query the database for the information you typed in, and if it is in the database, it will log me into the program. If not, it will display a message saying information is not correct.
Here is what I have so far.
private void okButton_Click(object sender, RoutedEventArgs e)
{
try
{
SqlConnection UGIcon = new SqlConnection();
UGIcon.ConnectionString = "XXXXXXXXX; Database=XXXXXXXX; User Id=XXXXXXX; password=XXXXXXXXX";
UGIcon.Open();
SqlCommand cmd = new SqlCommand("SELECT User(Username, '') AS Username, User(Password,'') AS Password, FROM User WHERE Username='"
+ txtUsername.Text + "' and Password='" + txtPassword.Password + "'", UGIcon);
SqlDataReader dr = cmd.ExecuteReader();
string userText = txtUsername.Text;
string passText = txtPassword.Password;
while (dr.Read())
{
if (this.userText(dr["stUsername"].ToString(), userText) &&
this.passText(dr["stPassword"].ToString(), passText))
{
MessageBox.Show("OK");
}
else
{
MessageBox.Show("Error");
}
}
dr.Close();
UGIcon.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
But, the only problem is it does not work at all. I am not sure I have the correct statements to query the database either. I am also getting an error on the "this.userText" As well.
{
if (this.userText(dr["stUsername"].ToString(), userText) &&
this.passText(dr["stPassword"].ToString(), passText))
{
For the error I'm getting, it tells me the WPF does not contain a definition for it
I am a little unsure of how to fix it and go about it as this is the first time I've had to do this. But I think I have a decent start to it though.
There are a couple of things wrong with this structure:
this.userText(dr["stUsername"].ToString(), userText)
First, userText isn't a function, it's a local variable. So I'm not sure what you're even trying to do by invoking it as a function. Are you just trying to compare the variable? Something like this?:
this.userText.Equals(dr["stUsername"].ToString())
Second, the error is telling you that the object doesn't contain a definition for userText because, well, it doesn't. When you do this:
this.userText
you're specifically looking for a class-level member called userText on the object itself. But your variable is local to the function:
string userText = txtUsername.Text;
So just drop the this reference:
userText.Equals(dr["stUsername"].ToString())
Third, the column reference is incorrect. Note how you define the columns in your SQL query:
SELECT User(Username, '') AS Username, User(Password,'') AS Password ...
The column is called Username, not stUsername:
userText.Equals(dr["Username"].ToString())
Edit: #Blam made a good point in a comment, which demonstrates a logical error in the code. If no results are returned from your query, the while loop will never execute. So no message will be shown. You can check for results with something like HasRows:
if (dr.HasRows)
MessageBox.Show("OK");
else
MessageBox.Show("Error");
This kind of renders the previous things moot, of course. But it's still good to know what the problems were and how to correct them, so I'll leave the answer whole for the sake of completeness regarding the overall question.
A few other notes which are important but not immediately related to your question...
Your code is vulnerable to SQL injection attacks. You'll want to look into using parameterized queries instead of concatenating string values like that. Essentially what this code does is treat user input as executable code on the database, allowing users to write their own code for your application.
Please don't store user passwords in plain text. The importance of this can not be overstated. The original text of a password should never be readable from storage. Instead, store a hash of the password. There's a lot more to read on the subject.
Look into using blocks to dispose of resources when you're done with them.
SqlCommand cmd = new SqlCommand("SELECT count(*) FROM User WHERE Username='"
+ txtUsername.Text + "' and Password='" + txtPassword.Password + "'", UGIcon);
Int32 rowsRet = (Int32)cmd.ExecuteScalar();
if(rowsRet > 0)
{
MessageBox.Show("OK");
}
else
{
MessageBox.Show("Error");
}
You still have exposure to SQL injection attack.
Related
I am trying to redirect my login.htm to index.htm in c#. both files are inside the folder named 'default'. after logging in, if the credential is correct, I want to redirect the login page to index. using the code below, but there is an exception message Attempted to cancel thread.. Is there a way to fix this?? How you can help me. Thanks in advance.
[WebMethod]
public void LogMeIn(string user, string pass) {
try {
using (MySqlConnection dbConn = new MySqlConnection(connectionString())) {
if (dbConn.State == System.Data.ConnectionState.Open) dbConn.Close();
dbConn.Open();
MySqlCommand sqlCmd = new MySqlCommand("SELECT * FROM tbllogin WHERE userName = '" + user + "' AND passWord ='" + pass + "'", dbConn);
int rowCount = (int)sqlCmd.ExecuteScalar();
if (rowCount > 0) {
HttpContext.Current.Response.Redirect("../default/index.htm"); //redirect to new htm page
}
}
}
catch (Exception ex) {
Console.WriteLine("Error Message : " + ex.Message);
}
}
HttpContext.Current.Response.Redirect(HttpContext.Current.Request.ApplicationPath+"default/index.htm");
Or you can use this way.
HttpContext.Current.Response.Redirect is trying to send users to the wrong place
HttpContext.Current.Response.Redirect("~/default/index.htm");
There are some errors and unnecesary code in your code example:
There is no need to check if dbConn is already opened, because it was just created
The SELECT * caused an Exception when doing later an ExecuteScalar because the table has more than one column. You should change it to SELECT COUNT(*)
Because how Microsoft handles how the flow of the page is done, if you don't end the response when doing the Response.Redirect you may need to catch an ThreadAbortException. To end the response you could check Redirect(string url, bool endResponse) overload
That being said, you should do use parametrized queries, because unexpected or malicious input could cause you problems.
I have a software which displays some tables from our SQL database. Now I want to add a tool, where I can change the password for my "testdummy" user.
I tried to open a connection again but it didn't help. If you need some additional code or informations, just write a comment.
Notice that I'm new to programming. I'm a apprentice and currently learning programming and administer databases. I know this is not the safest solution, but it's just a little task from my instructor. This software will not be released for customers.
Like I mentioned before, I tried to open a connection again before I want to change the password.
public void Change()
{
SqlConnection con = new SqlConnection();
string connectionString = GetConnectionString();
if (NewPassword.Password == NewPasswordAgain.Password && OldPassword.Password == GlobalData.Password)
{
try
{
//dbMan.TryConnect(connectionString);
//con.Open();
SqlConnection.ChangePassword($"Data Source={GlobalData.ServerName};Initial Catalog={GlobalData.DBName};UID={GlobalData.Username};PWD={OldPassword}", $"{NewPassword}");
}
catch (SqlException ex)
{
MessageBox.Show("Unable to change password. Try again!" + ex);
}
}
else
{
// If new Password doesn't match.
MessageBox.Show("Passwords doesn't match!");
}
}
I'm getting a SQL exception when I am trying to change the password.
(System.Data.SqlClient.SqlException (0x80131904): Login failed for user 'csharptest'.
I get this at:
SqlConnection.ChangePassword($"Data Source={GlobalData.ServerName};Initial Catalog={GlobalData.DBName};UID={GlobalData.Username};PWD={OldPassword}", $"{NewPassword}");
At this point of the programm, there should be a connection to the database, because I can handle some tables and manipulate the data sets.
But when I uncomment this:
//dbMan.TryConnect(connectionString);
//con.Open();
It goes into the catch brackets there:
public bool TryConnect(string connectionString)
{
conn = new SqlConnection();
conn.ConnectionString = connectionString;
try
{
conn.Open();
return true;
}
catch (Exception)
{
MessageBox.Show("Couldn't connect");
return false;
}
}
and returns following exception:
System.InvalidOperationException: 'Die ConnectionString-Eigenschaft wurde nicht initialisiert.'
In english it should be something like: "the connectionstring property has not been initialized"
Edit:
In the logs I'm getting this:
Login failed for user 'csharptest'. Reason: Password did not match that for the login provided.
Edit:
Instead of:
SqlConnection.ChangePassword($"Data Source={GlobalData.ServerName};Initial Catalog={GlobalData.DBName};UID={GlobalData.Username};PWD={OldPassword}", $"{NewPassword}");
I did this:
string updatePassword = "USE CSHARPTEST ALTER LOGIN [" + GlobalData.Username + "] WITH PASSWORD = '" + NewPassword + "'";
con.Open();
cmd.ExecuteNonQuery();
And now I think the only problem is the permission on the server.
You need to use parameters at the DbContext level. See this answer for more details, but, here's a code example (adapted from that same page):
string sql = "ALTER LOGIN #loginName WITH PASSWORD = #password";
ctx.Database.ExecuteSqlCommand(
sql,
new SqlParameter("loginName", loginName),
new SqlParameter("password", password));
The purpose of using the parameters here (and everywhere) is to prevent a SQL injection attack. This is especially important given that you are writing code that changes a password.
UPDATE
The ALTER LOGIN statement won't work with variables; it must be done through dynamic SQL. Here's an example of the updated code:
string sql = #"DECLARE #sql NVARCHAR(500)
SET #sql = 'ALTER LOGIN ' + QuoteName(#loginName) +
' WITH PASSWORD= ' + QuoteName(#password, '''')
EXEC #sql ";
ctx.Database.ExecuteSqlCommand(
sql,
new SqlParameter("loginName", loginName),
new SqlParameter("password", password));
Note we're still using the SqlParameters to prevent SQL injection attacks. We are also using the T-SQL method QuoteName to do proper quoting in the SQL we are generating; but this method simply doubles any [ characters (in the first call) or ' characters (in the second). There are many other vectors for a SQL injection attack, so merely relying on QuoteName wouldn't be enough.
I have registration form. In this case it will simply contain USERNAME and PASSWORD.
When I created the table in SQL Server, i put both columns on NOT NULL but when I try to register without entering either username or password there are no errors and my forms 'registrates' new user for example without password (if I didn't enter password).
Here is my code so if anyone can help me with that problem, and also to say if anything other is wrong/poorly written with the code because I'm new in all of this. I think I did good on SQL injection problem but you never know. Thank you very much on your reply.
private void button1_Click(object sender, EventArgs e)
{
SqlConnection cn = new SqlConnection("Data Source=HOME-PC;Initial Catalog=TestDB1;Integrated Security=True");
try
{
cn.Open();
String query = "INSERT INTO dbo.users (uUsername, uPassword) VALUES (#uUsername, #uPassword)";
SqlCommand command = new SqlCommand(query, cn);
command.Parameters.AddWithValue("#uUsername", textBox1.Text);
command.Parameters.AddWithValue("#uPassword", textBox2.Text);
command.ExecuteNonQuery();
MessageBox.Show("OK");
this.usersTableAdapter.Fill(this.testDB1DataSet.users);
}
catch (Exception ex)
{
MessageBox.Show("Error");
}
finally
{
cn.Close();
}
}
If I've understood this correctly, you have an application written in C# that interacts with an SQL Server back end.
You should be able to add a check in the C# code to check if the text boxes are empty or not when you click on the button. My C# is very rusty but it could be done thus:
if (string.IsNullOrWhiteSpace(textBox1.Text) || string.sNullOrWhiteSpace(textBox2.Text))
{
messagebox.show("Invalid entry");
}
Sadly I don't have Visual Studio to check this, but I'd check the text boxes aren't empty before doing the SQL stuff.
Also I'd change the name of your textboxes to something you'll remember, otherwise you'll find it a nightmare when it comes to maintaining your code.
I'm trying to make a login program that will check what the user entered in with usernames and passwords that are saved in a database. for some reason, the "if(dr.HasRows)" part of the program is not working. When i try without the try catch, i get and error "possible mistaken empty statement". What have i done wrong?
SqlConnection Connection = new SqlConnection(#"Data Source=(LocalDB)\v11.0;AttachDbFilename=|DataDirectory|\Logins.mdf;Integrated Security=True");
try
{
Connection.Open();
MessageBox.Show("Connection Succesful");
if (Connection != null && Connection.State == ConnectionState.Closed);
SqlCommand cmd = new SqlCommand("SELECT Count(*) FROM Logins WHERE Username='" + txtUsername.Text + "' and Password='" + txtPassword.Text + "'", Connection);
SqlDataReader dr = cmd.ExecuteReader();
if (dr.HasRows)
{
MessageBox.Show("Login Success");
}
else
{
MessageBox.Show("Incorrect login");
}
}
catch (Exception)
{
MessageBox.Show("Connection Unsuccesful");
}
This line
if (Connection != null && Connection.State == ConnectionState.Closed);
contains a semicolon that cause the warning, but you have just opened the connection, what is the purpose to add this check?
Then there are the Sql Injection and parsing problems caused by your string concatenation
I would change your code to
using(SqlConnection Connection = new SqlConnection(....))
{
try
{
Connection.Open();
SqlCommand cmd = new SqlCommand(#"SELECT Count(*) FROM Logins
WHERE Username=#uname and
Password=#pass", Connection);
cmd.Parameters.AddWithValue("#uname", txtUsername.Text);
cmd.Parameters.AddWithValue("#pass", txtPassword.Text);
int result = (int)cmd.ExecuteScalar();
if(result > 0)
MessageBox.Show("Login Success");
else
MessageBox.Show("Incorrect login");
}
catch(Exception ex)
{
MessageBox.Show("Unexpected error:" + ex.Message);
}
}
The parameterized approach is safer because it avoids the Sql Injection problem and move the job of properly quoting your values to the framework code. Also the command text is more readable.
I have also changed your code from ExecuteReader to ExecuteScalar because you need to retrieve only the first column of the first row returned by your query and don't need an SqlDataReader for that.
And the last thing that I need to say is: Catching exceptions just to say that something failed is not a good practice. At least, tell to your user what is the error. Use MessageBox.Show("Unexpected error: " + ex.Message)
EDIT OK sorry but I have another one. Storing passwords in clear text is really a big security problem. The right approach is to store an hash of the password and apply the hashing function to the parameter used to pass the password, in this way only the hash result is transmitted along the wire and, if someone manage to stole the database, it will be very difficult to revert back to the clear values
The possible empty statement is:
if (Connection != null && Connection.State == ConnectionState.Closed);
that ; at the end makes the if statement pointless.
On another note you should be using Parameters to pass your arguments not pasting the strings directly into the query to protect against an SQL injection attack.
Having said all that, your if (dr.HasRows) statement should still be working correctly, assuming the connection is actually valid etc.
I am trying to create a login page. I have a database table called Login, and it has two columns: ID and Password. It has the following ID and Password pairs in it: First row:(13282,123456), Second Row:(11111,11111). If username and password is right, i redirect page to succesful.aspx, if either username or password is wrong, i redirect page to unsuccesful.aspx. My problem is, When i enter 13283 as ID and 123456 as password, it does everything right, i am redirected to succesful page. But when i enter ID=11111 and Password=11111 even though everything is true, it redirects to unsuccesful page. I think the problem is, my query only checks the first row. Here is the code:
protected void loginButton_Click(object sender, EventArgs e)
{
SqlConnection con = new SqlConnection();
con.ConnectionString = "Data Source=.\\SQLEXPRESS;Initial Catalog=University;Integrated Security=True;Pooling=False";
Int32 verify;
string query1 = "Select count(*) from Login where ID='" + idBox.Text + "' and Password='" + passwordBox.Text + "' ";
SqlCommand cmd1 = new SqlCommand(query1, con);
con.Open();
verify = Convert.ToInt32(cmd1.ExecuteScalar());
con.Close();
if (verify > 0)
{
Response.Redirect("succesful.aspx");
}
else
{
Response.Redirect("unsuccesful.aspx",true);
}
}
Several things are wrong with this approach:
It requires storing passwords in plain text - This is the worst thing one can do to a user's password: anyone who accidentally gains access to your database would instantly be in possession of all your users' passwords, with is very, very bad.
It is susceptible to SQL Injection attacks - Concatenating strings to produce a SQL command is dangerous, because malicious users could enter strings that break your SQL and turn it into something else.
You should study the answers to this question. The approaches discussed there are not nearly as simple as what you are implementing, but they make your system a lot more bullet-proof.