What is the safest way to make SQL queries in c#? [duplicate] - c#

This question already has answers here:
How do parameterized queries help against SQL injection?
(6 answers)
Closed 4 years ago.
I'm working on a simple script to query a database based off user input, and I was wondering if there's any chance of injection with something like .net's parameterized queries?

By using the SqlCommand and its child collection of parameters all the pain of checking for sql injection is taken away from you and will be handled by these classes.
Here is an example, taken from Here:
private static void UpdateDemographics(Int32 customerID,
string demoXml, string connectionString)
{
// Update the demographics for a store, which is stored
// in an xml column.
string commandText = "UPDATE Sales.Store SET Demographics = #demographics "
+ "WHERE CustomerID = #ID;";
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlCommand command = new SqlCommand(commandText, connection);
command.Parameters.Add("#ID", SqlDbType.Int);
command.Parameters["#ID"].Value = customerID;
// Use AddWithValue to assign Demographics.
// SQL Server will implicitly convert strings into XML.
command.Parameters.AddWithValue("#demographics", demoXml);
try
{
connection.Open();
Int32 rowsAffected = command.ExecuteNonQuery();
Console.WriteLine("RowsAffected: {0}", rowsAffected);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}

Related

Struggling with Parameterized Insert Query [duplicate]

This question already has an answer here:
How to use OdbcParameter for MySQL?
(1 answer)
Closed 3 years ago.
I'm really struggling with creating a parameterized insert query in C# using OdbcConnection and MySQL. If I use string concatenation in the SQL statement it works fine. However, I need to accept user input from a textbox and this is vulnerable to SQL injection.
When I try to setup the parameterized query the command sorta works. A record is inserted into the database so I know the connection is being made and a record is able to be inserted. The issue is all the inserted field values are null as if it's not reading the parameters.
The following code works:
public static void Insert(string connectionString, Vendor vendor)
{
using (OdbcConnection connection = new OdbcConnection(connectionString))
{
string SQL = "INSERT INTO tbl_vendor (name) VALUES (\"" + vendor.Name + "\")";
using (OdbcCommand command = new OdbcCommand(SQL, connection))
{
connection.Open();
command.ExecuteNonQuery();
}
}
}
The following code inserts an empty record:
public static void Insert(string connectionString, Vendor vendor)
{
using (OdbcConnection connection = new OdbcConnection(connectionString))
{
string SQL = "INSERT INTO tbl_vendor (name) VALUES (#name)";
using (OdbcCommand command = new OdbcCommand(SQL, connection))
{
OdbcParameter parameter = new OdbcParameter("#name", vendor.Name);
command.Parameters.Add(parameter)
connection.Open();
command.ExecuteNonQuery();
}
}
}
I've tried a million different variations of the above code. They all seem to work but each time they only insert an empty record. I'm probably missing something obvious and making things more complicated than they need to be but what am I doing wrong?
Test specifying the dataType:
OdbcParameter parameter = new OdbcParameter("#name", OdbcType.VarChar);
parameter.Value = vendor.Name;
command.Parameters.Add(parameter);

C# MySQL Inserting Same Data into 2 Different Tables

So I tried making a code for adding 2 same data within 2 different tables which is
"studentinfo" and "logindb"
I tried doing this
enter code heprivate void buttonRegisterStudent_Click(object sender, EventArgs e)
{
String connection = "server=localhost;user id=root;password=root;persistsecurityinfo=True;database=votingdb";
//Inserting Data
String insertDataInfo = #"INSERT INTO studentinfo (firstname,lastname,username,password,email) values
('"+this.textBoxFirstName.Text+"','"+this.textBoxLastName.Text+"','"+this.textBoxUsername.Text+
"','"+ this.textBoxPassword.Text + "','"+ this.textBoxEmail.Text + "')";
String insertDataLogin = #"INSERT INTO logindb (username,password) values ('"+this.textBoxUsername.Text+"','"
+this.textBoxPassword.Text+"')";
//Connection
MySqlConnection con = new MySqlConnection(connection);
MySqlCommand datainfo = new MySqlCommand(insertDataInfo,con);
MySqlCommand datalogin = new MySqlCommand(insertDataLogin, con);
MySqlDataReader datareaderinfo;
MySqlDataReader datareaderlogin;
try
{
con.Open();
datareaderinfo = datainfo.ExecuteReader();
datareaderlogin = datalogin.ExecuteReader();
MessageBox.Show("Student Register Successfully!");
}
catch (Exception ex)
{
MessageBox.Show("Failed to Register" + ex);
}
}
Resulting to Error which says there may only one mysqldatareader in the code. How can I add the same data to the different tables?
Don't use a datareader if you don't want to read data. Simple use the ExecuteNonQuery on your command:
datainfo.ExecuteNonQuery();
And don't forget to open en close your connection!
You don't need a data reader for insert statements, you should simply use ExecuteNonQuery.
Please note that your current queries are a security hazard as they are vulnerable to SQL Injection attacks.
Instead of concatenating user inputs as strings to create your SQL statements, use parameterized queries.
For more information, read How can prepared statements protect from SQL injection attacks?
An improved version of the main parts in your code is this:
var insertDataInfo = #"INSERT INTO studentinfo (firstname,lastname,username,password,email) values
(#firstName, #lastName, #userName, #passwordHash, #email)";
var insertDataLogin = #"INSERT INTO logindb (username,password) values (#userName, #passwordHash)";
var datainfo = new MySqlCommand(insertDataInfo,con);
datainfo.Parameters.Add("#firstName", DbType.VarChar).Value = this.textBoxFirstName.Text;
datainfo.Parameters.Add("#lastName", DbType.VarChar).Value = this.textBoxLastName.Text;
datainfo.Parameters.Add("#userName", DbType.VarChar).Value = this.textBoxUsername.Text;
datainfo.Parameters.Add("#passwordHash", DbType.VarChar).Value = this.textBoxPassword.Text;
datainfo.Parameters.Add("#email", DbType.VarChar).Value = this.textBoxEmail.Text;
var datalogin = new MySqlCommand(insertDataLogin, con);
datalogin.Parameters.Add("#userName", DbType.VarChar).Value = this.textBoxUsername.Text;
datalogin.Parameters.Add("#passwordHash", DbType.VarChar).Value = this.textBoxPassword.Text;
datainfo.ExecuteNonQuery();
datalogin.ExecuteNonQuery();
Also, you are storing passwords as plain text in your database.
That's a really big security hole. You should be storing salted hash values of your passwords instead - but that's getting a little too broad for this answer so I'll leave that part up for you to read and apply.

Protect my app from SQL Injection [duplicate]

This question already has answers here:
How can prepared statements protect from SQL injection attacks?
(10 answers)
Closed 4 years ago.
For now I execute a search in database and display the result with
string keyWord = textBoxSearch.Text.ToString();
using (SqlConnection con = new SqlConnection(conString))
{
try
{
con.Open();
if (con.State == ConnectionState.Open)
{
using (SqlCommand cmd = new SqlCommand("SELECT articleCode, articleName FROM Article WHERE articleName LIKE '" + keyWord + "%'", con))
{
// Put search result in dataGrid
}
}
}
}
Now following SqlCommand.Parameters example I should do something like
string cmdQuery = "SELECT articleCode, articleName from Article WHERE articleName LIKE #articleName'";
using (SqlConnection con = new SqlConnection(conString))
{
using (SqlCommand cmd = new SqlCommand(cmdQuery, con))
{
cmd.Parameters.Add("#articleName", SqlDbType.NVarChar);
cmd.Parameters["#articleName"].Value = textBoxSearch.Text;
try
{
// Put search result in dataGrid
}
}
}
But I don't really see how different this is because I still have to use the raw textBoxSearch.Text value.
Am I doing this right ?
To protect a web site from SQL injection, you can use SQL parameters.
SQL parameters are values that are added to an SQL query at execution time, in a controlled manner.
Example:
txtUserId = getRequestString("UserId");
sql = "SELECT * FROM Customers WHERE CustomerId = #0";
command = new SqlCommand(sql);
command.Parameters.AddWithValue("#0",txtUserID);
command.ExecuteReader();
The SQL engine checks each parameter to ensure that it is correct for its column and are treated literally, and not as part of the SQL to be executed.
View this for more details.
And yes, you can still use the textbox to take in value.

Incorrect Syntax near '=' (not an issue with "similiar" characters)

I know that this probably has been answered before, but I have rewritten this single line 10 times it still won't work. I have assured myself that this is written properly, yet it won't work.
This is my last resort. Here's a screenshot:
For security reasons, and for the exact reason you are asking, you should not be setting raw T-SQL in theCommandText property of your SqlCommand.
In your case, your string likely has ' characters in it that are breaking your query making the syntax invalid.
Instead, you CommandText should be initialized with Parameters, for example:
findItForMe.CommandText = "SELECT Name, LicenseType, till FROM myTable WHERE SomeColumn = #SomeParameter"
Then in your findItForMe command add the Parameters.
findItForMe.Parameters.AddWithValue("#SomeParameter", Somevalue)
Building your findItForMe SqlCommand this way will fix your errors and prevent malicious actors from perform SQL injection hacks against your application.
A full example:
string name = "Jacob's Ladder";
string commandText = "SELECT Name, LicenseType, till FROM myTable WHERE Name = #Name";
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlCommand findItForMe = new SqlCommand(commandText, connection);
// Use AddWithValue to assign name
// The parameterized query will escape your strings and keep you safe from hackers.
command.Parameters.AddWithValue("#name", name);
try
{
connection.Open();
SqlDataReader dr = command.ExecuteReader();
while (dr.Read())
{
// do something here
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}

how to update a table using oledb parameters?

I am having a table which has three fields, namely LM_code,M_Name,Desc. LC_code is a autogenerated string Id, keeping this i am updating M_Name and Desc. I used normal update command, the value is passing in runtime but the fields are not getting updated. I hope using oledb parameters the fields can be updated.
Here is my code.
public void Modify()
{
String query = "Update Master_Accounts set (M_Name='" + M_Name + "',Desc='" + Desc + "') where LM_code='" + LM_code + "'";
DataManager.RunExecuteNonQuery(ConnectionString.Constr, query);
}
In DataManager Class i am executing the query string.
public static void RunExecuteNonQuery(string Constr, string query)
{
OleDbConnection myConnection = new OleDbConnection(Constr);
try
{
myConnection.Open();
OleDbCommand myCommand = new OleDbCommand(query, myConnection);
myCommand.ExecuteNonQuery();
}
catch (Exception ex)
{
string Message = ex.Message;
throw ex;
}
finally
{
if (myConnection.State == ConnectionState.Open)
myConnection.Close();
}
}
private void toolstModify_Click_1(object sender, EventArgs e)
{
txtamcode.Enabled = true;
jewellery.LM_code = txtamcode.Text;
jewellery.M_Name = txtaccname.Text;
jewellery.Desc = txtdesc.Text;
jewellery.Modify();
MessageBox.Show("Data Updated Succesfully");
}
This annoyed me, screwy little OleDB, so I'll post my solution here for posterity. It's an old post but seems like a good place.
OleDB doesn't recognize named parameters, but it apparently does recognize that you're trying to convey a named parameter, so you can use that to your advantage and make your SQL semantic and easier to understand. So long as they're passed in the same order, it'll accept a variable as a named parameter.
I used this to update a simple Access database in a network folder.
using (OleDbConnection conn = new OleDbConnection(connString))
{
conn.Open();
OleDbCommand cmd = conn.CreateCommand();
for (int i = 0; i < Customers.Count; i++)
{
cmd.Parameters.Add(new OleDbParameter("#var1", Customer[i].Name))
cmd.Parameters.Add(new OleDbParameter("#var2", Customer[i].PhoneNum))
cmd.Parameters.Add(new OleDbParameter("#var3", Customer[i].ID))
cmd.Parameters.Add(new OleDbParameter("#var4", Customer[i].Name))
cmd.Parameters.Add(new OleDbParameter("#var5", Customer[i].PhoneNum))
cmd.CommandText = "UPDATE Customers SET Name=#var1, Phone=#var2" +
"WHERE ID=#var3 AND (Name<>#var4 OR Phone<>#var5)";
cmd.ExecuteNonQuery();
cmd.Parameters.Clear();
}
}
It may look like an excess of code, and yes you're technically repeating yourself, but this makes it worlds easier when you're playing connect-the-dots later on.....
You are close with the rest of your connection and such, but as you note, doing it with parameterized queries is safer from SQL-Injection...
// Some engines used named parameters, others may not... The "?"
// are "place-holders" for the ordinal position of parameters being added...
String MyQuery = "Update MyTable set SomeField = ?, AnotherField = ? "
+ " where YourKeyField = ?";
OleDbCommand MyUpdate = new OleDbCommand( MyQuery, YourConnection );
// Now, add the parameters in the same order as the "place-holders" are in above command
OleDbParameter NewParm = new OleDbParameter( "ParmForSomeField", NewValueForSomeField );
NewParm.DbType = DbType.Int32;
// (or other data type, such as DbType.String, DbType.DateTime, etc)
MyUpdate.Parameters.Add( NewParm );
// Now, on to the next set of parameters...
NewParm = new OleDbParameter( "ParmForAnotherField", NewValueForAnotherField );
NewParm.DbType = DbType.String;
MyUpdate.Parameters.Add( NewParm );
// finally the last one...
NewParm = new OleDbParameter( "ParmForYourKeyField", CurrentKeyValue );
NewParm.DbType = DbType.Int32;
MyUpdate.Parameters.Add( NewParm );
// Now, you can do you
MyUpdate.ExecuteNonQuery();
Just to add to RJB's answer, it's a little-known fact that OleDb actually DOES accept named parameters. You've just got to declare the parameters in SQL as well.
See: low-bandwidth.blogspot.com.au/2013/12/positional-msaccess-oledb-parameters.html
If you DON'T declare the parameters in SQL, OleDb uses purely positional parameter insertion, and it doesn't matter if the names of the parameters match the SQL, or if parameters are used twice in the SQL - it will just go through and blindly replace any found parameters in the SQL in order from start to end, with those passed.
However if you DO declare the parameters correctly, you get the benefit of named parameters and parameters allowed to be repeated multiple times within the SQL statement.

Categories

Resources