sql injection issue - asp.net

I have the following code snippet.
SqlCommand cmd = new SqlCommand("SELECT FName,LName FROM EMPLOYEE_TABLE WHERE EmployeeID = '" +TextBox1.Text + "' AND Password = '"+ TextBox2.Text +"'", con);
SqlDataReader x = cmd.ExecuteReader();
try
{
if (x.Read())
{
name = (string)x["FName"] +' '+ (string)x["LName"];
Session["NAME"] = name;
Session["ID"] = TextBox1.Text;
Response.Redirect("sample.aspx?action=On_Click");
}
else
{
errormsg.Text = "login failed.Please enter Valid UserID and Password";
errormsg.ForeColor = System.Drawing.Color.Red;
}
}
catch (Exception exp)
{
errormsg.Text = "Sorry,You dont have access to this portal.";
}
finally
{
x.Close();
con.Close();
}
Now, when i use a valid id (that exists) and password as abc' or 'x'='x then it logs in into the first account of the table in the database. Till this it's fine.
However when I try to debug the code, it throws an error Unable to evaluate expression because the code is optimized or a native frame is on top of the call stack..
Also if it is throwing an error then why is it logging into this 1st account of the database. Note: the first account of the database has a different userid than that which i m providing.
Note: I am the developed of this application. So I'm not doing anything illegal. :)

Look at this part of your SQL:
"' AND Password = '"+ TextBox2.Text +"'"
With your password, it's
"' AND Password = ''x'='x'"
which is not the SQL you want.
Even if you are trying to do SQL injection, you have to result in valid SQL. Usually, it's by ending the statement with a semi-colon after closing the quote. See this:
http://xkcd.com/327/

OK, to provide an answer based on the primary issue you've got (as you've stated, you're new to the SQL Injection issue).
SQL Injection is caused by dynamically building a SQL query using user input as part of the construction. The simplest solution to this in .Net is to create a parameterized query.
I think Jeff Atwood has the most complete yet concise article providing an explanation and complete example here
Quoted from above link:
SqlConnection conn = new SqlConnection(_connectionString);
conn.Open();
string s = "SELECT email, passwd, login_id, full_name " +
"FROM members WHERE email = #email";
SqlCommand cmd = new SqlCommand(s);
cmd.Parameters.Add("#email", email);
SqlDataReader reader = cmd.ExecuteReader();
The issue at hand:
The reason it's still logging into the account is because the query is still "valid".
The statement will still be executed, and the relevant record will still be returned from the database, no exception will be thrown.
The only way you will stop the login process when invalid data is provided is to validate the input before executing the query. You should always validate user input before sending it off to the database. If the user were to provide:
username'; drop table users;--
as the username, you would be in a LOT of trouble.

The error you're encountering is a debugging error, not an actual program exception. That's why it works when you run it normally.
To remedy the error, I'd first make sure that everything is running with a Debug build. Also, make sure you're currently debugging in the function of the variable you want to inspect. Try stepping (F10) a few times past your breakpoint to refresh the context. There are a slew of other suggestions on the internet for that particular error, so if you're still having problems you might have to do some googling.

Related

Unable to update database with the Window Form Application

I am trying to update my database with the window form I have created, however an error occurred when I execute the code:
An unhandled exception of type 'System.InvalidOperationException'
occurred in System.Data.dll" at comm.ExecuteNonQuery();
Here is the code that I used to connect to my database. Was the code I used to update the database wrong?
string conn=ConfigurationManager.ConnectionStrings["MyConnection"].ConnectionString;
SqlConnection connection = new SqlConnection(conn);
SqlCommand comm = new SqlCommand("UPDATE ExerciseInstruction SET Accumulated_Daily_Sets_Completed = '0' WHERE ExerciseInstructionsID ='" + exerciseInstructionID +"'", connection);
comm.ExecuteNonQuery();
Here is the complete error message :
ExecuteNonQuery requires an open and available Connection. The
connection's current state is closed.
The error message explain all. The command cannot be executed if the code doesn't know how to reach the database. Just a call to connection.Open should fix the problem, however I think you need to use a proper way to execute the query.
This is called Parameterized query. In this way you don't concatenate strings together to form you query text but use parameters to pass values to the database engine and a special formatted string containing the parameters placeholders.
There are two main advantages to do so. It is not possible to target your code with Sql Injection hacks and you don't have to handle quoting around your strings (an infinite source of bugs)
string conn=ConfigurationManager.ConnectionStrings["MyConnection"].ConnectionString;
string cmdText = #"UPDATE ExerciseInstruction
SET Accumulated_Daily_Sets_Completed = 0
WHERE ExerciseInstructionsID =#exid";
using(SqlConnection connection = new SqlConnection(conn))
using(SqlCommand comm = new SqlCommand(cmdText, connection))
{
connection.Open(); // Need this before executing the query
comm.Parameters.Add("#exid", SqlDbType.Int).Value = exerciseInstructionID;
comm.ExecuteNonQuery();
}

oracleDatareader.ExecuteReader() not returning any data

I have written a code in ASP.NET to fetch data from Oracle database. The code returns data from locally hosted Oracle DB but when I am pointing towards the remote OracleDB, nothing comes. However, if I run same query on the remote DB using SQL Developer Tool, it works fine.
I have debugged my code for right SQL statement and it is absolutely correct.
Following is my code snippet
using (Oracle.DataAccess.Client.OracleConnection con = new
Oracle.DataAccess.Client.OracleConnection())
{
con.ConnectionString = ConfigurationManager.ConnectionStrings["ca_eFormsVSED"].ConnectionString;
con.Open();
// query for fetch username and market
String sql = "a valid query"
Oracle.DataAccess.Client.OracleCommand cmd = new Oracle.DataAccess.Client.OracleCommand(sql, con);
cmd.CommandType = CommandType.Text;
if (con.State == ConnectionState.Open)
{
Oracle.DataAccess.Client.OracleDataReader dr = cmd.ExecuteReader();
}
if (dr.Read())
{
//Do Something
}
}
Please suggest how to make it work.
I got the solution of this problem and it may help some one else. If you are 100% sure that code is correct and current SQL statement returns data from database, then check carefully your database tables have dependency or not. Remove existing tables and import new data again and it works fine for me.

Securing data before update

I have a few text boxes that on my page that can add data to my database. What I'm looking for is how to actually make it more secure. The basic error checking of empty text boxes I know how to check. What I'm really searching for is bad data being saved or special characters like " ' " or " - ". Its a simple application only myself and maybe two other people will use it but still want to make sure learning and coding correctly. Any suggestions. This is my save button.
Here is my code:
try
{
OleDbConnection conn = new OleDbConnection(#"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=H:\Databases\AddressBook.mdb");
conn.Open();
DataSet ds = new DataSet();
string cmd = "SELECT * FROM tblAddressBook";
OleDbDataAdapter da = new OleDbDataAdapter(cmd, conn);
da.Fill(ds, "Display");
DataRow newRow = ds.Tables["Display"].NewRow();
newRow[1] = txtFirstName.Text;
newRow[2] = txtLastName.Text;
newRow[3] = txtEmail.Text;
newRow[4] = txtPhone.Text;
ds.Tables["Display"].Rows.Add(newRow);
OleDbCommandBuilder cb = new OleDbCommandBuilder(da);
cb.DataAdapter.Update(ds.Tables["Display"]);
conn.Close();
GridView1.DataBind();
}
catch (Exception)
{
lblErrorSave.Text = "Your information did not save clear form and try again";
}
Your code as shown is secure, but does have problems.
What your question is about is SQL Injection. This arises where you use dynamic SQL, like so (air code):
string sql = "insert into tableA (cola, colb) values ("
+ "'" + txtBox1.Text + "',"
+ "'" + txtBox2.Text + "')";
...and then go and execute it. Depending on the contents of the text boxes you could have all sorts of things happening. Something like "');drop table tableA;--"
This does not happen when you use a DataSet as above, so that's OK
Hoewever, your code is very inefficient. The first thing you do is pull down the whole of the Address table. If this is any size it will be slow and add a lot of IO, memory, and computation to the procedure.
You are also not checking that the row to be entered is actually a new one, not a modification of an old one or a duplicate. This may or may not be important to your app, but usually is important (dup data can be a real pain). You can amend your read of the Address table to pull down e.g. a row with the same email address (or whatever is unique), and if it gets it then amend with new data as you do above.
However if the data is to be added, then you need to use parameters; Air Code again:
string sql = "insert into table (colA, colB) values (#colA, #colB)";
using (OleDbCommand com = new OleDbCommand(sql, conn))
{
com.Parameters.Add("#colA", txtBox1.Text);
com.Parameters.Add("#colB", txtBox2.Text);
com.ExecuteNonQuery();
}
(Note that different drivers have slightly different syntax on adding Parameters and I'm not sure that the OleDb command supports this syntax, but there will be something close.)
Using Parameters prevents SQL Injection, as the values of the parameters are transported not intermixed in the SQL string and so their content has no effect of the SQL eventually executed.

Calling stored procedure from asp.net doesn't work

I wrote a stored procedure to update PAID column in tblUser, and that stored proceudre works perfectly,
Code:
#buyer_email varchar(50),
#payment bit
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
update tblUser set paid=#payment where email = #buyer_email
END
but when I call it from my asp.net app then it doesn't update the Paid column, even if I try simple update statement in my asp.net code but that also doesn't update the column.
String userEmail_send = (Convert.ToString(Request.QueryString["emailAdmin"]));
String conString = "Data Source=COSANOSTRA; MultipleActiveResultSets=true; Initial Catalog=Waleed_orsfinal;Integrated Security=True";
try
{
con.Open();
if (userEmail_get.Replace("'", string.Empty) == userEmail_send.Replace("''", string.Empty))
{
//String query1 = "update tblUser Set paid=1 where email='" + userEmail_send + "' ";
SqlCommand sqlcom1 = new SqlCommand("submitPaypalPayment", con);
sqlcom1.CommandType = CommandType.StoredProcedure;
sqlcom1.Parameters.Add("#buyer_email", SqlDbType.VarChar).Value = userEmail_send;
sqlcom1.Parameters.Add("#payment", SqlDbType.Bit).Value= 1 ;
sqlcom1.ExecuteScalar();
hdr_msg_success.InnerText = "Congrats, You have paid successfully. Wait for an approval by an admin ";
Response.Write("<br/>"+" "+ "Matched=" +userEmail_send.Replace("''","'"));
}
else
{
hdr_msg_success.InnerText = "Something went wrong in matching Emails , Please confirm your Email";
}
}
catch (Exception exc)
{
Response.Write(exc.Message);
}
finally
{
con.Close();
}
The failure is likely due to your connectionstring security context.
Assuming you're running under IIS impersonation of the current web user is not the default behavior.
By specifying Integrated Security=True in your connectionstring you're telling SQL Server to accept the current Windows context as the user attempting to gain access to the database. This will be the IIS Application Pool account, not your own account, when running under IIS.
Try creating a SQL Server user name and password and specifying them in the connectionstring instead of using integrated security with a web application. You could alternatively set the Application Pool Windows Identity but that's something that's usually more cumbersome to maintain and migrate... There's also the option of allowing web user impersonation but that's even more unwieldy.
By the way, here are some other things to consider...
Store your connectionstring in a config file, not hardcoded (I understand that this may just be test code, but if not...)
Consider interacting with your stored procedure from ADO.net with something more like this in your use case.
using (SqlCommand sqlcom1 = new SqlCommand("dbo.submitPaypalPayment", con))
{
sqlcom1.CommandType = CommandType.StoredProcedure;
sqlcom1.Parameters.Add("#buyer_email", SqlDbType.VarChar) { Value = userEmail_send };
sqlcom1.Parameters.Add("#payment", SqlDbType.Bit) { Value= 1 };
sqlcom1.ExecuteNonQuery();
}
Based on what I read here, I seems like the values are not set correctly to the variables from the Request object.
Have you tried setting the break point and check what value is set to your userEmail_send variable from this statement
[String userEmail_send = (Convert.ToString(Request.QueryString["emailAdmin"]));]?
May be its not setting the right value for that variable.
Set the break point at this line sqlcom1.ExecuteScalar(); and check the parameter values.
You can do that by the ordinal position or by the name of the parameter as shown below:
By ordinal position sqlcom1.Parameters[0].Value or by name sqlcom1.Parameters["#buyer_email"].Value
do the same thing for your #payment parameter as well. Remember its ordinal position would be 1.
Hope, this helps... and good luck...

Creating a Registration form: In asp.net

I'm new to Asp.net, and creating a online telephone bill payment form. A new user has to register to get a valid id,
In the SQL Server I created a table which has only two columns as Phone_number and User_name. I have set the Phone_number column as unique. Just to avoid re-registration of a user.
I have checked the form during runtime using asp.net web page but, i get some error in the code.
Also I have to display a message that "the phone number already exists."
my code is as follows. Is there a better way??
try
{
string s = " insert into new_user values(#Phone_number,#name)";
cmd = new SqlCommand(s, con);
cmd.Parameters.AddWithValue(#"Phone_number", TextBox1.Text);
cmd.Parameters.AddWithValue(#"Name", TextBox2.Text);
cmd.ExecuteNonQuery();
}
catch (SqlException ex)
{
Console.WriteLine(ex);
MessageBox.Show("Phone Number already exist, Enter a different phone number");
}
TextBox1.Text = TextBox2.Text = null;
Session["a"] = TextBox1.Text;
Response.Redirect("registration.aspx");
}
in the above code if I don't user the Console.Writeline(); I get an error in the ExecuteNonQuerry() part.
I suggest that First you check, Is there same phone no available in database?
Just use select query , If you get any record you can display a message and if not exist any record then use insert query.
If(select * from table where phone=#Phone)
insert command
else
message

Resources