Query doesn't add parameters' value when executed - c#

I want to insert multiple rows into my database, I tried to use parameters but I did something wrong.
In debug mode, the parameters do have values, but once the insert is done, I still have #compte, #mo, #userimp in my database instead of their values.
string INSERTDELAMORTPart2 = "'123'," + "'#compte'" + "," + "'#mo'" + "," + "'ubs'" + "," + "'2'" + "," + "'#userimp'" + "," + "'22.10.17'" + ",'";
OdbcCommand Query = new OdbcCommand(INSERTDELAMORTPart2, InfoConnexion);
Query.Parameters.AddWithValue("#compte", _cb_Compte.SelectedItem);
Query.Parameters.AddWithValue("#mo", MondantResultat);
Query.Parameters.AddWithValue("#userimp", UserImp);
Query.ExecuteNonQuery();
I have tried Parameters.Add, and also Parameters["#name"].Value, but the result stays the same.
What am I doing wrong ?
EDIT :
I have an Oracle database and I need the single quote to insert my values.
I have tried to pass my whole INSERT string into a parameter but it doesn't work.
I'm about to give up and just replace the ' by '' even if it's a bad idea.

A few things.
If you are using Oracle, I highly recommend you use ODP.net or managed ODP.net, not ODBC. ODBC should work, but the native drivers will work more efficiently and will avoid any oddities you might with with the abstraction layer ODBC provides. Managed ODP.net has the additional advantage of not requiring an Oracle client be installed on the target machine
SQL Server (and other databases) use the "#" as a parameter, but Oracle uses the colon ":" instead. Some databases (like PostgreSQL) will take either. While the parameter in your SQL requires the colon, when you use assign the parameter in .NET you need to omit it. Again, this is an Oracle thing you won't find in other databases.
Your SQL doesn't appear to have any command in it... only values. Where is your "insert into?"
Especially with Oracle, you want to be explicit about your datatypes... so use Add instead of AddWithValue (which is actually an overload of Add in ODP.net). Alternatively, you can set the datatype later.
The converted code would look something like this:
string insert = "insert into my_table values (:COMPTE, :MO, :USERIMP)";
using (OracleCommand cmd = new OracleCommand(insert, Connection))
{
// no ":" in the parameter declarations
cmd.Parameters.Add(new OracleParameter("COMPTE", OracleDbType.Int32));
cmd.Parameters.Add(new OracleParameter("MO", OracleDbType.Varchar2));
cmd.Parameters.Add(new OracleParameter("USERIMP", OracleDbType.Varchar2));
cmd.Parameters[0].Value = 123;
cmd.Parameters[1].Value = "ubs";
cmd.Parameters[2].Value = "22.10.17";
cmd.ExecuteNonQuery();
}
I guessed at your datatypes -- make sure they match your DDL when you actually implement this, and if these aren't the only three columns, update your insert command appropriately.
If for some reason I misunderstood, and this is not Oracle, I still recommend use of the native driver rather than ODBC. When you use ODBC, you assume a lot about the target machine -- assumptions that may not turn out to be true.

The command should look something like this:
insert into t(compte, mo, userimp) -- of course the table and columns should be the right names
values (#compte, #mo, #userimp);
No single quotes are needed.
I would recommend against using AddWithValue(). Instead, be explicit about the types.

You have this:
string INSERTDELAMORTPart2 = "'123'," + "'#compte'" ...
Note the single quotes around the parameter names. They should not be there. You want this instead:
string INSERTDELAMORTPart2 = "'123'," + "#compte"

Related

Create Database Dynamically Using C#

I am trying to create a database using this code:
var createDatabaseQuery = "exec ('CREATE DATABASE ' + #db)";
var sqlCommand = new SqlCommand(createDatabaseQuery, sqlConnection);
sqlCommand.Parameters.Add("#db", SqlDbType.Text);
sqlCommand.Parameters["#db"].Value = "DbName";
sqlCommand.ExecuteNonQuery();
The above works perfectly but I try to do concatenation as follows, it throws an exception:
var sqlCommand = new SqlCommand(createDatabaseQuery, sqlConnection);
sqlCommand.Parameters.Add("#db", SqlDbType.Text);
sqlCommand.Parameters["#db"].Value = "DbName" + CustomId; //Doing the concatenation here
Exception:
System.Data.SqlClient.SqlException (0x80131904): Incorrect syntax near '-'
I know, there could be better ways to do it. But is there any way that I can make the above work?
Time to learn the real intricate sides of SQL.
The way you wan t to write it - is incorrect in multiple ways. DEBUG THE SQL. Do not care about the C# code, look at the SQL...
In your case - naming conversions.
Tables, databases etc. can not contains a "-" - OR they must be marked.
CREATE DATABASE my-database -> Error
CREATE DATABASE [my-database] -> correct, the [] brackets names and thus... no processing of the "-" is tried.
This is quite clear in the SQL documentation, but a part many people overlook (mostly because in most cases it does not matter). They likely wonder why generators bracket every item name (Database, schema, table, COLUMN). Well, that is the reason. What do you think "-1" means? Minus one, processing, or part of a name - the server has no way to determine this. Help him.
You need to make sure you are quoting the name correctly using QUOTENAME, because it contains characters that need escaping.
var createDatabaseQuery = "exec ('CREATE DATABASE ' + QUOTENAME(#db))";
Also, the parameter type should be nvarchar(128)
sqlCommand.Parameters.Add("#db", SqlDbType.NVarChar, 128).Value = "DbName" + CustomId;

ORA-01036 - illegal variable name/number

I have a dynamic SQL for searching records in Oracle, and VS2017 code analysis reports warning about using parameterized SQL query for this line (1st line, this code works):
string SQL = "SELECT " + string.Join(",", my_columns.ToArray()) + " FROM MyTable ";
string where_condition = " WHERE ";
//the rest of code follows as this...
if (!string.IsNullOrEmpty(textbox1.Text))
{
SQL = string.Concat(SQL, where_condition, " Name like :name");
cmd.Parameters.Add(new OracleParameter("name", string.Concat("%", textbox1.Text, "%")));
where_condition = " AND ";
} //...
So, I tried to put column names as parameters because of warning, but then I get ORA-01036- illegal variable name/number error:
string SQL = "SELECT :columns FROM MyTable ";
cmd.Parameters.Add(new OracleParameter("columns", string.Join(",",
my_columns.ToArray())));
string where_condition = " WHERE ";
What is wrong, maybe column names cannot be passed as parameters ? Or is there any other way to avoid warning in VS code analysis ?
You're right - column names can't be passed as parameters. That part has to be done dynamically, unless you want to change your database structure very significantly. (You could have one column with a value which is the logical column name, and one column for the value. I'm not recommending this - it's very much not how databases are intended to be used.)
The warning you're getting is there to avoid SQL injection attacks. When building the query dynamically, you have to do that differently. You basically need to make sure you have a whitelist of column names, and only build up SQL including those names.
You may well still get a code analysis warning at that point, but you should disable that just for this piece of code, with a comment explaining that you understand the warning, and what you've done to remove the risk of SQL injection attacks.

SQLInjection with Npgsql/Postgres

I want to learn how SQLInjection is working with the PostgresqlDb. I am using the Npgsql in C#.
So this is my Query, which is called, when I rename a folder:
cmd.CommandText = "UPDATE allfolder.folder SET folder_name = '" + foldernamenew + "'";
cmd.ExecuteNonQuery();
I now tried to pass the following value into the textfield:
abcdef; INSERT INTO allfolder.folder (id, folder_name) VALUES (56,"aaaaaaa");
Then AJAX is fired.
The output I assumed is, that all folders in the table has the folder_name "abcdef" and that I have a new folder with the id "56" called "aaaaaa". This is not the case, because the semicolon is not recognized as delimiter and so the name of each folder_name are "abcdef; INSERT INTO ....". I do not want to change it on DB side that multiqueries are allowed.
So my questions are:
How do I need to prepare the SQL statement, that I achieve a Injection?
Is an injection even possible, when you are not allowed to execute a second qry because the semicolon isn't recognized?
I am only talking about Npgsql and postgres.
As Laurenz mentioned above, this should work:
abcdef'; INSERT INTO allfolder.folder (id, folder_name) VALUES (56,'aaaaaaa'); -- test
Make sure, that you don't mix single and double quotes. A common mistake in SQL. You need the single quote before the semicolon, otherwise it is in the textstring, because you have no delimiter.
“Multiqueries” (several queries in one line, separated by semicolon) are always allowed in PostgreSQL.
Your problem are the multiple errors in your SQL:
Missing single quote after abcdef.
Double quotes instead of single quotes around aaaaaaa.
No single quote or line comment at the end of the statement.
Speaking pointedly: you have to learn SQL before you can learn SQL injection.

A simple SQL problem: Making an SQL insert statement with text string that contain ' characters

I follow the syntax of
INSERT INTO Table1
VALUES (value1, value2, value3…)
This has worked fine so far. But now I have some values that contain normal English text like "I'm going home". The ' character ruins the SQL command in C#. I have written the following:
command.CommandText = "INSERT INTO Bio VALUES ('" + name + "','"I'm going home" + "');
evaluates to
INSERT INTO Bio VALUES ('Peter','I'm going home')
which obviously will not work. How do I make sure special character will not ruin the SQL statements?
Use SqlParameter for heaven's sake. Otherwise your program will be vulnerable to SQL Injection. It will also solve your problem with the special characters.
Learn about parameterized queries for your provider. They exists for Odbc, OleDb, Sql, etc.
command.CommandText = "INSERT INTO Bio Values (#name, #text)";
command.Parameters.Add(/* appropriate param type for your provider */); // add for #name, #text, etc.
// execute query
Use two single quotes whenever there is a single quote you want to escape
Also instead of building your queries like this, you should use parameterized queries in a language of your choice. Escaping the characters yourself opens the door for SQL Injections.
Usually you can escape a single quote by screening with another one.
For example the following is a valid statement
INSERT INTO myTable (Column1) VALUES ('Hello I''m Jack');
However I suggest you using parameters.
command.CommandText = "INSERT INTO Bio VALUES (#Name, #OtherValue)";
command.Parameters.AddWithValue("Name", name);
command.Parameters.AddWithValue("OtherValue", "I'm going home");
One addition point in favor of using parameters is that you are free from burden of formatting and other stuff. I mean date values, uniqueidentifiers, etc.
I do use
HttpUtility.HtmlEncode(text)
It makes all that SQL injection stuff disappear, and it seems easier than to use parameters.
Don't forget to use
HttpUtility.HtmlDecode(text)
to get your input back in the form you received it

is it safe using dynamic SQL with parameters? If not, what security issues might it be exposed to?

For example, this is the code that I am using:
String commandString = "UPDATE Members SET UserName = #newName , AdminLevel = #userLevel WHERE UserID = #userid";
using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["sqlconnectionstring"].ConnectionString))
{
SqlCommand cmd = new SqlCommand(commandString, conn);
cmd.Parameters.Add("#newName", newName);
cmd.Parameters.Add("#userLevel", userLevel);
cmd.Parameters.Add("#userid", userid);
conn.Open();
cmd.ExecuteReader();
Reader.Close();
}
That code looks fine. Parameterisation is the way to go, as opposed to concatenating user-supplied values in an adhoc SQL statement which can open you up to sql injection attacks. This can also help with execution plan reuse.
The only thing I'd add, is I prefer to explicitly define the datatype and sizes of the parameters. For example, if you don't then, as an example, all string values will get passed in to the database as NVARCHAR instead of VARCHAR. Hence I like to be explicit.
It's safe against SQL injection because it's parameterized. Other security concerns, such as ensuring that #userid is not spoofed, are separate security concerns that should be dealt with in other layers of your application.
That's still a static query string. It's not really "dynamic" sql until you also build parts of the string on the fly — something like this:
var sql = "SELECT columns FROM Table WHERE 1=1";
if (!string.IsNullOrEmpty(txtName.Text)) sql += " AND Name LIKE '%' + #Name + '%'";
if (!string.IsNullOrEmpty(txtDesc.Text)) sql += " AND CONTAINS(DESCRIPTION, #description)";
But even so, this is still "safe" in the sql injection sense as long as you continue to use parameters for every part of the query that originates with user input.

Categories

Resources