How to use string variable in sql statement - c#

I have a WPF Application in which I am getting
string someone = TextBox.text;
I would like to use this in the following query
query = " Select * From Table Where Title = someone "
How should I go about using the variable someone in the query?

You can just do this
query = "Select * From Table Where Title = " + someone;
But that is bad and opens you to SQL Injection
You should just use a parameterized query
Something like this should get you started
using (var cn = new SqlClient.SqlConnection(yourConnectionString))
using (var cmd = new SqlClient.SqlCommand())
{
cn.Open();
cmd.Connection = cn;
cmd.CommandType = CommandType.Text;
cmd.CommandText = "Select * From Table Where Title = #Title";
cmd.Parameters.Add("#Title", someone);
}
From Jon Skeet's answer since his was more complete than mine
See the docs for SqlCommand.Parameters for more information.
Basically you shouldn't embed your values within the SQL itself for various reasons:
It's inelegant to mix code and data
It opens you up to SQL injection
attacks unless you're very careful about escaping
You have to worry about formatting and i18n details for things like numbers, dates and
times etc
When the query remains the same with only the values
changing, the optimizer has less work to do - it can look up the
previous optimized query directly as it'll be a perfect match in
terms of the SQL.

You should use a parameterized SQL query:
query = "SELECT * From TableName WHERE Title = #Title";
command.Parameters.Add("#Title", SqlDbType.VarChar).Value = someone;
See the docs for SqlCommand.Parameters for more information.
Basically you shouldn't embed your values within the SQL itself for various reasons:
It's inelegant to mix code and data
It opens you up to SQL injection attacks unless you're very careful about escaping
You have to worry about formatting and i18n details for things like numbers, dates and times etc
When the query remains the same with only the values changing, the optimizer has less work to do - it can look up the previous optimized query directly as it'll be a perfect match in terms of the SQL.

Easiest is to use a C# Prepared sql. Example on this post. You don't have to worry about escaping the characters in your sql string or anything

declare #SqlQuery varchar(2000), #Fromdate varchar(20), #Todate varchar(20)
set #Fromdate='01 jan 2017'
set #Todate='30 mar 2017'
set #SqlQuery='select * from tblEmployee where tblEmployee.JDate between '''+ #Fromdate + ''' and '''+ #Todate+ ''''
print #SqlQuery

Related

How to generate a SQL Command string that is safe from SQL Injection?

I have a situation where I have to take input from a user, create a SQL command and send that command to a service that will execute the SQL. The service ONLY allows for a SQL string -- not additional parameters; so I am forced to create the entire SQL statement on my end of things.
I do not have any kind of access to the database itself -- only a service that sits overtop of it.
I realize the following is NOT safe:
var sql = $"SELECT * FROM tablename WHERE name = '{incomingdata.searchName}'";
But if I generate SQL with parameters, would this be safe from SQL injection?
var sql = $#"
DECLARE #Name varchar(50);
SET #Name = '{incomingdata.searchName}';
SELECT * FROM tablename WHERE name = #Name";
This is not an ideal situation. I would try and look for a parametrized way to solve this problem failing that I would test the input and in ANY case where a test fails not allow the query at all and ask the user to re-enter.
Do the following tests:
Length of input is smaller than a max name size (25 characters?)
All input characters are in the alphabet
No reserved SQL words (easy to find with a google search)
If the input does not fail any of these tests you should be OK. DON'T try to sanitize the input -- this can be hard/impossible to do with international character sets.
Disclosure: My background is C++, Java and TypeScript/JavaScript, not C#
Would this be more appropriate:
SqlCommand sql = new SqlCommand("SELECT * FROM tablename WHERE name = #Name");
sql.Parameters.Add("#Name", SqlDbType.VarChar, 50).Value = incomingdata.searchName);
Sanitizing the user data before it gets to this stage, using a trusted package, might also be helpful.
The second example is better, but still not fully secure.
SQL injection attacks can still occur if the input data is maliciously crafted, regardless of whether the input data is directly embedded into the string or used as a parameter.
A more secure way to handle this situation is to use parameterized queries, which automatically escape any special characters in the input data and prevent SQL injection attacks.
Unfortunately, if the service you are using only accepts raw SQL strings and does not support parameters, your options are limited. In this case, it is recommended to validate and sanitize the input data before constructing the SQL string to minimize the risk of SQL injection.
To make the SQL statement safe from SQL injection, you can use parameterized queries. In .NET, you can use the SqlCommand.Parameters property to define parameters and their values. The following is an example:
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
string sql = "SELECT * FROM tablename WHERE name = #Name";
using (SqlCommand command = new SqlCommand(sql, connection))
{
command.Parameters.AddWithValue("#Name", incomingdata.searchName);
using (SqlDataReader reader = command.ExecuteReader())
{
// process the results
}
}
}
In this example, the value of incomingdata.searchName is passed as a separate parameter and not directly concatenated into the SQL string. This protects against SQL injection because the parameter value is automatically escaped and properly formatted by the .NET framework.
You are along the right lines. You never want to use a variable that can be changed. Instead, you need to use SQL parameters. You can add a SQL parameter like this:
command.Parameters.Add(new SqlParameter("#Name", "incomingdata.searchName"));
And then refer to it in your query like this:
SELECT *
FROM tablename
WHERE name = #Name";
Once this is done, when a user tries to change the value of a variable the query will return no results. It should be said that this way of doing it does result in the SQL property assuming the type of the C# variable. There are other ways of doing this if you want to specify the type of the property to be different from the variables type. This is a useful resource https://jonathancrozier.com/blog/preventing-sql-injection-in-c-sharp-applications

Parameters and SQL Injection asp.net

I used parameters in the whereclause, but what about the variables for this {0}. Do I need to create a parameter for it to prevent sql injection?
("...inner join db1.dbo.table1.id on db2.dbo.table2.id = {0}.dbo.table3.id where name=#name",abc)
var abc = ddl2.SelectedItem.Text;
cmd.Parameters.AddWithValue("#name", ddl1.selectedvalue);
To the best of my knowledge, you can't actually 'paramaterize' database names/table names.
String.Format does not solve SQL injection in this case since it is possible for the user to change ddl2.SelectedItem.Text to whatever they want.
If you need a dynamic value for the database name, I suggest you either keep that value as a const or store it somewhere that you have complete control over/ is never sent or interpreted client side.
I would suggest you to use any ORM (object relational mapping) i.e Entity framework or n-hibernate etc. and use linq to write queries, that will prevent you application from SQL Injection.
Unfortunately, as Abbath already mentioned, this type of construct is not parameterizable. As Abbath mentioned, the best solution is to keep such arguments under your absolute control, but there are times, where such constructs are needed, and it may not be possible to have complete control over them.
For such scenarios, the best recommendation in this case is to escape the arguments. In this case, the DB name represented by {0} on your sample code.
There are two potential mechanisms to achieve this:
a) Create a mechanism that allows you to parameterize the query
Advantage: You can reuse the same solution from any driver (.Net, ODBC, etc.)
Disadvantage: A bit more work. You will not use select directly anymore on this case.
For example (I am including a simple example that has an inner join, just like your code):
CREATE PROC sp_MyQuery( #target_db_name sysname, #name nvarchar(100))
AS
BEGIN
DECLARE #cmd nvarchar(max)
DECLARE #parameters nvarchar(max)
SELECT #cmd = N'SELECT * FROM msdb.sys.objects inner join '
+ quotename(#target_db_name) + N'.sys.sql_modules
on msdb.sys.objects.object_id = '
+ quotename(#target_db_name) + N'.sys.sql_modules.object_id WHERE name = #name'
print #cmd -- See the command before it is executed.
set #parameters = N'#name nvarchar(100)'
EXEC sp_executesql #cmd, #parameters, #name = #name
END
go
-- Example of usage
DECLARE #target_db_name sysname = 'msdb'
DECLARE #name nvarchar(100) = 'sp_help_operator'
EXEC sp_MyQuery #target_db_name, #name
go
At this point, you can use SqlParameter objects as you would normally do. For example:
sqlcmd.CommandText = #"[dbo].[sp_MyQuery]";
sqlcmd.CommandType = System.Data.CommandType.StoredProcedure;
sqlcmd.Parameters.AddWithValue("#target_db_name", ddl0.selectedvalue);
sqlcmd.Parameters.AddWithValue("#name", ddl1.selectedvalue);
SqlDataReader reader = sqlcmd.ExecuteReader();
b) Escape the DB name within your CLR code
Advantage: Easier to implement
Disadvantage: App-specific solution, you need to be careful with potential Unicode–DB collation translation issues.
For example (same query as above):
sqlcmd.CommandText = String.Format(#"
SELECT * FROM msdb.sys.objects inner join [{0}].sys.sql_modules on msdb.sys.objects.object_id = [{0}].sys.sql_modules.object_id WHERE name = #name;",
ddl0.selectedvalue.Replace("]", "]]"));
sqlcmd.CommandType = System.Data.CommandType.Text;
sqlcmd.Parameters.AddWithValue("#name", ddl1.selectedvalue);
SqlDataReader reader2 = sqlcmd.ExecuteReader();
I typically recommend using solution (a) whenever it is possible, but both solutions should help you protect against SQL injection.
BTW. The following link may also be quite useful: https://blogs.msdn.microsoft.com/raulga/2007/01/04/dynamic-sql-sql-injection/
I hope information helps.
you dont need create parameter for abbc if you use string.format like this
var abc = ddl2.SelectedItem.Text;
string.format("...inner join db1.dbo.table1.id on db2.dbo.table2.id = {0}.dbo.table3.id where name=#name",abc)
cmd.Parameters.AddWithValue("#name", ddl1.selectedvalue);

SqlCommand shows bad performance when passing text parameter for LIKE

I've encountered quite a wierd problem:
I form SQL server command dynamically and one of its part is a group of LIKE tests, that are used as textual search on several columns and tables. It looks like:
SET #text = '%' + REPLACE(REPLACE(REPLACE(#text, '!', '!!'), '%', '!%'), '_', '!_') + '%'
INSERT INTO
#textFiltered
FROM
#documents d
LEFT JOIN docData t1 WITH (NOLOCK)
ON t1.ID = d.ID AND
(t1.Topic like #text escape '!'
OR t1.Subject like #text escape '!')
LEFT JOIN docData2 t2 WITH (NOLOCK)
ON t2.ID = d.ID AND
t2.Name like #text escape '!'
WHERE
t1.ID IS NOT NULL
OR t2.ID IS NOT NULL
(Surely, that's not the best way to do textual search, still that's not the point)
Now, when I create SQLCommand in C#, like this:
using (var cmd = new SqlCommand())
{
cmd.CommandText = cmdText;
cmd.CommandType = CommandType.Text;
cmd.Connection = connection;
cmd.Parameters.Add("text", NVarChar, 4000).Value = searchText;
var reader = cmd.ExecuteReader();
....
}
performce of executing is very poor (say, 8 seconds), while executing same query in SQL Management Studio much faster (say, 500 ms).
However, if instead of passing text as parameter, I embed it into text of SQL with:
DECLARE #text nvarchar(max)
SET #text = '<embedded-text>'
then SqlCommand also runs fast.
What's even more strange this behavior seems to be correlated with set of columns that are used in LIKE clauses (didn't figure how). Types of those columns can be nvarchar(size), nvarchar(max), ntext.
I suspect that problem is with parameter - maybe it's type is incorrect or smth else.
P.S. Tried to create parameter with size = length of searched text + 1 - didn't help.
My best guess will be that it is related to the query plan that SQL Server is choosing for you.
there is big difference between using constant varchar which the SQL server can evaluate against existing statistics, and using arbitrary variable which the server know nothing about.
you can try OPTION (RECOMPILE) hint. although this hint will cause the Stored procedure to be compiled on every call, it'll also allow the SQL Server to search for the best plan for the given values, and maybe in your case it will be good trade off.
you could also add the query plan for both option of the stored procedure, and maybe someone will be able to see the difference, and pin point the exact problem.

How to SELECT with optional columns?

I'm currently working on a c# application that grabs a bunch of data from a user specified access(.mdb) database and does a bunch of stuff with that data. A problem that I've recently come across is that some of the a database is missing a column that has existed in all of the others.
How can I do a select on a database, but gracefully fail (throw null in the data or something) when a column doesn't exist in the database?
Currently, my code looks something like this:
OleDbConnection aConnection = new
OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + FileName);
string sqlQuery = "SELECT [Table1].[Index], [Table1].[Optional Info],
[Table2].[Other Info], ....
FROM [Table1] INNER JOIN [Table2] ON [Table1].[Index]=[Table2].[Index]
ORDER BY [Table1].[Index]";
OleDbCommand aCommand = new OleDbCommand(sqlQuery, aConnection);
OleDbDataReader aReader = aCommand.ExecuteReader();
(proceed to read data in line by line, using fabulous magic numbers)
I think it's obvious that this is one of my first experiences with databases. I'm not overly concerned as long as it works, but it's stopped working for a database that does not contain the [Table1].[Optional Info] column. It's throwing an OleDbException: "No value given for one or more required parameters."
Any help would be appreciated.
I might be missing something but...
SELECT Table1.*, Table2.otherInfo
FROM ...
Should do the trick, and let the client process the result set, with an important caveat: there is no way to exclude a column from Table1 in the above.
(I am not aware of any method to "dynamically shape" -- with the viewpoint of the caller -- a SELECT except with a * in the column list as above.)
Happy coding.
The way to do that is to not use magic numbers, but to fetch the field names from the reader and use them - for example GetName etc.
Alternatively, use a mapper like "dapper" that will do this for you.
There is no way to do this in a single query: you cannot run a query that includes columns that don't exist in the source tables. When the server tries to compile the query, it will simply fail.
If you absolutely need to support different scemas, you will need different queries for each of them.
To make things even more awesome, there is no documented way to check if an Access table has a particular column on it via SQL. In SQL Server, you could query the system schema, like sys.objects or sys.columns. In Access, the MsysObjects table has the information you need but it's schema is liable to change on you without notice.
Probably the safest way to go about this is to do a single, up front check where you execute a command such as
SELECT * FROM Table1
then scan the resulting column names to see if your optional column exists; your C# code would then become:
string sqlQuery = string.Empty;
if (optionalColumnExists)
{
sqlQuery = "SELECT [Table1].[Index], [Table1].[Optional Info], -- etc."
}
else
{
sqlQuery = "SELECT [Table1].[Index], '' AS [Optional Info], -- etc."
}
There is a way to extract the table schema using OleDbDataReader.GetSchemaTable and that can be used
OleDbConnection aConnection = new
OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + FileName);
OleDbCommand aCommand = new OleDbCommand("Table1", aConnection);
aCommand.CommandType = CommandType.TableDirect;
aConnection.Open();
OleDbDataReader aReader = cmd.ExecuteReader(CommandBehavior.SchemaOnly);
DataTable schemaTable = aReader.GetSchemaTable();
aReader.Close();
aConnection.Close();
bool optionalInfoColumnExists = schemaTable.Columns.Contains("Optional Info");
Now later in the code
string sqlQuery = #"SELECT [Table1].[Index], {0}
[Table2].[Other Info], ....
FROM [Table1] INNER JOIN [Table2] ON [Table1].[Index]=[Table2].[Index]
ORDER BY [Table1].[Index]";
if (optionalInfoColumnExists)
{
sqlQuery = string.Format(sqlQuery, "[Table1].[Optional Info],");
}
else
{
sqlQuery = string.Format(sqlQuery, "");
}
and while reading use similar logic.
I don't know what kind of application this is but the optionalInfoColumnExists should be populated at the application or session start and reused throughout the life of the app i.e. don't execute the GetSchemaTable everytime a query is run on this table (assuming that the mdb won't change while the app is active).
Either way, it seems like that it is going to make the code to have "if else" just to take care of presense and absence of a column in a table.

How do parameterized queries help against SQL injection?

In both queries 1 and 2, the text from the textbox is inserted into the database. What's the significance of the parameterized query here?
Passing txtTagNumber as a query parameter
SqlCommand cmd = new SqlCommand("INSERT INTO dbo.Cars " +"VALUES(#TagNbr);" , conn);
cmd.Parameters.Add("#TagNbr", SqlDbType.Int);
cmd.Parameters["#TagNbr"].Value = txtTagNumber.Text;
Converting txtTagNumber to an integer before constructing the query
int tagnumber = txtTagNumber.Text.ToInt16(); /* EDITED */
INSERT into Cars values(tagnumber.Text); /* then is it the same? */
Also, here I would use Regular Expression validation to stop insertion of illegal characters.
Parameterized queries do proper substitution of arguments prior to running the SQL query. It completely removes the possibility of "dirty" input changing the meaning of your query. That is, if the input contains SQL, it can't become part of what is executed because the SQL is never injected into the resulting statement.
Imagine a dynamic SQL query
sqlQuery='SELECT * FROM custTable WHERE User=' + Username + ' AND
Pass=' + password
so a simple sql injection would be just to put the Username in as ' OR
1=1-- This would effectively make the sql query:
sqlQuery='SELECT * FROM custTable WHERE User='' OR 1=1-- ' AND PASS='
+ password
This says select all customers where they're username is blank ('') or
1=1, which is a boolean, equating to true. Then it uses -- to comment
out the rest of the query. So this will just print out all the
customer table, or do whatever you want with it, if logging in, it
will log in with the first user's privileges, which can often be the
administrator.
Now parameterized queries do it differently, with code like:
sqlQuery='SELECT * FROM custTable WHERE User=? AND Pass=?'
parameters.add("User", username) parameters.add("Pass", password)
where username and password are variables pointing to the associated
inputted username and password
Now at this point, you may be thinking, this doesn't change anything
at all. Surely you could still just put into the username field
something like Nobody OR 1=1'--, effectively making the query:
sqlQuery='SELECT * FROM custTable WHERE User=Nobody OR 1=1'-- AND
Pass=?'
And this would seem like a valid argument. But, you would be wrong.
The way parameterized queries work, is that the sqlQuery is sent as a
query, and the database knows exactly what this query will do, and
only then will it insert the username and passwords merely as values.
This means they cannot effect the query, because the database already
knows what the query will do. So in this case it would look for a
username of "Nobody OR 1=1'--" and a blank password, which should come
up false.
Source: lavamunky.com; Nov 2011
SQL injection happens when a possible parameter has SQL within it and the strings are not handled as it should be
eg:
var sqlquerywithoutcommand = "select * from mytable where rowname = '" + condition+''";
and the condition is a string coming from the user in the request. If condition is malicious
say eg:
var sqlquerywithoutcommand = "select * from mytable where rowname = '" + "a' ;drop table mytable where '1=1"+"'";
you could end up running malicious scripts.
However, using parameters the input will be cleaned of any characters which might escape string characters, which means you can be ensured no matter what comes in it will not be able to run inject scripts.
Using the command object with parameters the SQL actually executed would look like this:
select * from mytable where rowname = 'a'';drop table mytable where 1=1'''
in essence it will be looking for a row with rowname = a';drop table mytable where 1=1'
and not running the remaining script.
Parameterized queries handles everything - why go to the trouble?
With parametrized queries, in addition to general injection, you get all the data types handled, numbers (int and float), strings (with embedded quotes), dates and times (no formatting problems or localization issues when .ToString() is not called with the invariant culture and your client moves to a machine with and unexpected date format).
Parameterized queries allow the client to pass the data separately form the query text.
Where on most free from text you would do validation + escaping.
Of course Parameterization don't help against other kind of injection, but as the parameter are passed separately, they are not use as execution text query.
A good analogy would be the "recent" execution bit used with most of the modern processor and Operating system to protect from buffer overflow. It still allows the buffer overflow but prevent the execution of the injected data.
It is quite understandable why one would feel so.
sqlQuery = "select * from users where username='+username+';"
vs
sqlQuery = "select * from users where username=#username;"
Both the above queries seem to do the same thing.But they actually don't.
The former uses input to for a query, the latter decides on the query but only substitutes the inputs as it is during the execution of the query.
To be more clear, the parameters' values are located some where on the stack where the variables' memory is stored and is used for search when needed.
So if we were to give ' OR '1'='1 as the input in username, the former would dynamically construct a new queries or queries as part of the sql query string sqlQuery which is then executed.
While on the same input, latter would search for ' OR '1'=' in the username field of the users table with the statically specified query in the query string sqlQuery
Just to consolidate it, this is how you use parameters to make query:
SqlCommand command = new SqlCommand(sqlQuery,yourSqlConnection);
SqlParameter parameter = new SqlParameter();
parameter.ParameterName = "#username";
parameter.Value = "xyz";
command.Parameters.Add(parameter);

Categories