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);
Related
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);
}
}
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.
I am currently working on a dummy project in which I am making a login screen. I don't have any big intentions with the project, beside learning some C# and sql.
I am currently trying append a new user to the database which contains each username and their password, but I am for some reason getting an error message.
The entry written in the textbox should be stored in the database, but for some reason is this not happening..
I am getting an error stating I have a syntax error which I am not sure i understand.
private void create_user_username_box_Leave(object sender, EventArgs e)
{
// Add user/password to database when when someone leaves the area.
using (DbConnection connection = new SqlConnection(#"Server=localhost\SQLEXPRESS01;Database=master;Trusted_Connection=True;"))
{
connection.Open();
using (DbCommand command = new SqlCommand("INSERT INTO [dbo].[information] (id,password) VALUES ("+create_user_username_textbox.Text+","+create_user_password_textbox.Text+");"))
{
command.Connection = connection;
command.ExecuteNonQuery(); // System.Data.SqlClient.SqlException: 'Incorrect syntax near ')'.'
}
}
}
Do not do the following, ever
"INSERT INTO [dbo].[information] (id,password)
VALUES (" + someStringVariable + "," + someOtherStringVariable + ")"
Just think about what you're doing here - you're putting whatever text the user entered directly into your query string. This is the easiest way to have your database dropped or all the information it contains stolen.
Instead, use prepared statements
var commandText = "INSERT INTO [dbo].[information] (id,password) VALUES (#Username, #Password)"
using (var command = new SqlCommand(commandText, connection))
{
command.Parameters.Add("#Username", SqlDbType.VarChar).Value = create_user_username_textbox.Text
command.Parameters.Add("#Password", SqlDbType.VarChar).Value = create_user_password_textbox.Text
command.ExecuteNonQuery();
}
You should also strongly consider NOT storing passwords in plain text
Updated with suggestion to replace Parameters.AddWithValue - obviously if the column type on your database is different, set it accordingly
The values are strings so the resulting SQL command text should enclose them within single quotes.
VALUES ('"+create_user_username_textbox.Text+"','"...
However, you should really parameterise the query to prevent the potential for Sql injection attacks.
Change the string to:
VALUES (#id,#pw)"))
Add parameters to the command:
command.Parameters.Add(new SqlParameter("#id", create_user_username_textbox.Text));
command.Paramaters.Add(new SqlParameter("#pw", create_user_password_textbox.Text));
try this -
private void create_user_username_box_Leave(object sender, EventArgs e)
{
// Add user/password to database when when someone leaves the area.
using (SqlConnection connection = new SqlConnection(#"Server=localhost\SQLEXPRESS01;Database=master;Trusted_Connection=True;"))
{
connection.Open();
using (SqlCommand command = new SqlCommand("INSERT INTO [dbo].[information] (id,password) VALUES ("+create_user_username_textbox.Text+","+create_user_password_textbox.Text+");"))
{
command.Connection = connection;
command.ExecuteNonQuery(); // System.Data.SqlClient.SqlException: 'Incorrect syntax near ')'.'
}
}
}
I have a C# web forms project built in VS2010 and I would like to move from using hard coded SQL queries to stored procedures to interrogate my SQL Server database so i can use parameters.
The code I am having difficulty with reads in data from the database using an sql data reader, and creates a comma separated string that i use for a list of available values for a textbox using jquery autocomplete.
This works fine when using hard coded sql but when i try and change this to a stored procedure and add parameters the textbox has no values available. When I debug this i can see that the code inside the while (reader.Read()) is not getting run. Meaning the code to create the comma separated string is not being run.
Using hard coded SQL (this works)
string mySQLQuery = "SELECT col1 from table1"
using (SqlConnection myConnection = new SqlConnection(ConfigurationManager.ConnectionStrings["myConnectionString"].ConnectionString))
using (SqlCommand command = new SqlCommand(mySQLQuery, myConnection))
{
myConnection.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
//code to create comma separated string
}
}
}
Converted to using stored procedure (this doesn't work)
using (SqlConnection myConnection = new SqlConnection(ConfigurationManager.ConnectionStrings["myConnectionString"].ConnectionString))
using (SqlCommand myCommand = new SqlCommand("storedProcedureName", myConnection))
{
myCommand.CommandType = CommandType.StoredProcedure;
myCommand.Parameters.Add("#param1", SqlDbType.VarChar).Value = value1;
myCommand.Parameters.Add("#param2", SqlDbType.VarChar).Value = value2;
myConnection.Open();
using (SqlDataReader reader = myCommand.ExecuteReader())
{
while (reader.Read())
{
//code to create comma separated string
}
}
}
Any help will be greatly appreciated
I thing the name of param should by without # but it is depends of database. I using without "#" to MSSQL and it works
I use # prefix only in sql command.
"Select * from table where name = #name"
Change this:
myCommand.Parameters.Add("#param1", SqlDbType.VarChar).Value = value1;
to this:
myCommand.Parameters.Add("param1", SqlDbType.VarChar).Value = value1;
for param2 is the same
I have managed to sort this out, the issue was to do with the values of parameters being passed to the stored procedure which is included in code that I didnt include.
The values were being passed to the stored procedure but the procedure was not returning any values which is why it appeared like the while(myreader.read()) line was being skipped.
The code now works fine, thanks everyone for your help.
using (var connection = new SqlConnection(...))
{
string sql = "SELECT * FROM tableA";
using (var command = new SqlCommand(sql,connection))
{
using (var reader = command.ExecuteReader(...))
{
//***************Sample Start
string sql2 = "INSERT into tableB(column1) VALUES('"+reader["column1"]+"')";
using (var command2 = new SqlCommand(sql2,connection))
{
...
}
//***************Sample End
}
}
}
By using the above code snippet, I believe its the best practice to deal with SQL in C#. Now after I retrieve a list of records from tableA, for each of the row I would like to insert into tableB.
However, it's throwing an exception
There is already an open DataReader associated with this Command which must be closed first
I know this problem can be solved by creating another method and insert into the table from there, I'm wondering if there is any other way. Thanks for any input.
You need to use a different sql connection for the insert than for the select...
...but we can do even better. You can re-write this to be one sql statement, like so:
INSERT into tableB(column1)
SELECT column1 FROM tableA
And then run it all at once like this:
string sql = "INSERT into tableB(column1, column2) SELECT column1, #othervalue As column2 FROM tableA;";
using (var connection = new SqlConnection(...))
using (var command = new SqlCommand(sql,connection))
{
command.Paramters.Add("#othervalue", SqlDbType.NVarChar, 50).Value = "something";
connection.Open();
command.ExecuteNonQuery();
}
The single sql statement is typically much faster, and you end up with less code, too. I understand that this is likely a simplified example of your real query, but I promise you: you can re-write it all as one statement.
Additionally, sometimes you still want to do some client-side processing or display with the new records after the insert or update. In that case, you still only need to send one call to the database, but there will be two separate sql statements in that single call. The final code would look more like this:
string sql = "INSERT into tableB(column1, column2) SELECT column1, #othervalue As column2 FROM tableA;"
sql += "SELECT columnn1, #othervalue As column2 FROM tableA;";
using (var connection = new SqlConnection(...))
using (var command = new SqlCommand(sql,connection))
{
command.Paramters.Add("#othervalue", SqlDbType.NVarChar, 50).Value = "something";
connection.Open();
using (var reader = command.ExecuteReader() )
{
while (reader.Read() )
{
//...
}
}
}
And because someone else brought up MARS (multiple active result sets), I'll add that while this can work, I've had mixed results using it for inserts/updates. It seems to work best when everything that shares a connection is only doing reads.
As has been mentioned in comments, you need a separate database connection for the insert. Each connection can handle one active statement at a time, and you have two here - one for the SELECT, one (at a time) for the INSERT.
Try this for instance:
string srcqry = "SELECT * FROM tableA";
using (SqlConnection srccon = new SqlConnection(ConnectionString))
using (SqlCommand srccmd = new SqlCommand(srcqry, srccon))
{
srccon.Open();
using (SqlDataReader src = srccmd.ExecuteReader())
{
string insqry = "INSERT INTO tableB(column1) VALUES(#v1)";
// create new connection and command for insert:
using (SqlConnection inscon = new SqlConnection(ConnectionString))
using (SqlCommand inscmd = new SqlCommand(insqry, inscon))
{
inscmd.Parameters.Add("#v1", System.Data.SqlDbType.NVarChar, 80);
inscon.Open();
while (src.Read())
{
inscmd.Parameters["#v1"].Value = src["column1"];
inscmd.ExecuteNonQuery();
}
}
}
}
Using parameters solves the SQL Injection vulnerability. You should always do this rather than building the query string from raw user input, or from data that you're pulling from a database, or... well, always. Write some helper methods to make it easier if you like, just make sure you do it.
aside from a bad example, why not just simplify the query to
insert into TableB (column1) select column1 from TableA