In some C# code, table names passed in via an enum are being inserted into SQL queries using string.Format like so:
const string ADD_SQL = "INSERT INTO {0} (ColumnOne) VALUES (#valueOne)";
const string CLEAR_SQL = "DELETE FROM {0}";
var commandText = string.Format(ADD_SQL , _tableName);
But when I run the Veracode tool it shows this query has possibility of SQL injection when executing.
command.ExecuteNonQuery();
I want to avoid the possibility of SQL injection with the above code. I tried adding a tag (#tablename), but that did not work.
const string ADD_SQL = "INSERT INTO #tablename (Data) VALUES (#valueOne)";
var commandText = ADD_MESSAGE_SQL.Replace("#tablename", _tableName);
How do I avoid this?
There is a good chance that Veracode does not like you putting SQL queries like your current statements, and instead wants to use it's prescribed way of writing this code. And as visible in the documentation in the Repair section, it wants you to use prepared statement to create a parameterized query.
It's upto your choice now. My take on this would be that stored procedures will be better, but if you have to keep query in C#, just don't try to make one query too generic for all scenarios and tables.
Concatenating strings into SQL statements is risky if your strings comes from user input.
While that is not the case you described, I'm guessing the Veracode tool doesn't know where the strings come from, it just see string concatenation and issue a warning.
A better approach would be to write complete SQL statements for each table (Usually I prefer using stored procedures, but that's another topic [you can search for stored procedures vs inline SQL]) and use parameters for values (Identifiers can't be parameterized in SQL, as you already found out).
So instead of
const string ADD_SQL = "INSERT INTO {0} (ColumnOne) VALUES (#valueOne)";
const string CLEAR_SQL = "DELETE FROM {0}";
and adding the table names at run time, here is a better solution:
const string ADD_tableName = "INSERT INTO TableName (ColumnOne) VALUES(#ValueOne)"
const string CLEAR_tableName = "DELETE FROM TableName";
There are even better solutions out there, but this is the easiest fix for the code you presented.
Related
I am very new to working with databases. Now I can write SELECT, UPDATE, DELETE, and INSERT commands. But I have seen many forums where we prefer to write:
SELECT empSalary from employee where salary = #salary
...instead of:
SELECT empSalary from employee where salary = txtSalary.Text
Why do we always prefer to use parameters and how would I use them?
I wanted to know the use and benefits of the first method. I have even heard of SQL injection but I don't fully understand it. I don't even know if SQL injection is related to my question.
Using parameters helps prevent SQL Injection attacks when the database is used in conjunction with a program interface such as a desktop program or web site.
In your example, a user can directly run SQL code on your database by crafting statements in txtSalary.
For example, if they were to write 0 OR 1=1, the executed SQL would be
SELECT empSalary from employee where salary = 0 or 1=1
whereby all empSalaries would be returned.
Further, a user could perform far worse commands against your database, including deleting it If they wrote 0; Drop Table employee:
SELECT empSalary from employee where salary = 0; Drop Table employee
The table employee would then be deleted.
In your case, it looks like you're using .NET. Using parameters is as easy as:
string sql = "SELECT empSalary from employee where salary = #salary";
using (SqlConnection connection = new SqlConnection(/* connection info */))
using (SqlCommand command = new SqlCommand(sql, connection))
{
var salaryParam = new SqlParameter("salary", SqlDbType.Money);
salaryParam.Value = txtMoney.Text;
command.Parameters.Add(salaryParam);
var results = command.ExecuteReader();
}
Dim sql As String = "SELECT empSalary from employee where salary = #salary"
Using connection As New SqlConnection("connectionString")
Using command As New SqlCommand(sql, connection)
Dim salaryParam = New SqlParameter("salary", SqlDbType.Money)
salaryParam.Value = txtMoney.Text
command.Parameters.Add(salaryParam)
Dim results = command.ExecuteReader()
End Using
End Using
Edit 2016-4-25:
As per George Stocker's comment, I changed the sample code to not use AddWithValue. Also, it is generally recommended that you wrap IDisposables in using statements.
You are right, this is related to SQL injection, which is a vulnerability that allows a malicioius user to execute arbitrary statements against your database. This old time favorite XKCD comic illustrates the concept:
In your example, if you just use:
var query = "SELECT empSalary from employee where salary = " + txtSalary.Text;
// and proceed to execute this query
You are open to SQL injection. For example, say someone enters txtSalary:
1; UPDATE employee SET salary = 9999999 WHERE empID = 10; --
1; DROP TABLE employee; --
// etc.
When you execute this query, it will perform a SELECT and an UPDATE or DROP, or whatever they wanted. The -- at the end simply comments out the rest of your query, which would be useful in the attack if you were concatenating anything after txtSalary.Text.
The correct way is to use parameterized queries, eg (C#):
SqlCommand query = new SqlCommand("SELECT empSalary FROM employee
WHERE salary = #sal;");
query.Parameters.AddWithValue("#sal", txtSalary.Text);
With that, you can safely execute the query.
For reference on how to avoid SQL injection in several other languages, check bobby-tables.com, a website maintained by a SO user.
In addition to other answers need to add that parameters not only helps prevent sql injection but can improve performance of queries. Sql server caching parameterized query plans and reuse them on repeated queries execution. If you not parameterized your query then sql server would compile new plan on each query(with some exclusion) execution if text of query would differ.
More information about query plan caching
Two years after my first go, I'm recidivating...
Why do we prefer parameters? SQL injection is obviously a big reason, but could it be that we're secretly longing to get back to SQL as a language. SQL in string literals is already a weird cultural practice, but at least you can copy and paste your request into management studio. SQL dynamically constructed with host language conditionals and control structures, when SQL has conditionals and control structures, is just level 0 barbarism. You have to run your app in debug, or with a trace, to see what SQL it generates.
Don't stop with just parameters. Go all the way and use QueryFirst (disclaimer: which I wrote). Your SQL lives in a .sql file. You edit it in the fabulous TSQL editor window, with syntax validation and Intellisense for your tables and columns. You can assign test data in the special comments section and click "play" to run your query right there in the window. Creating a parameter is as easy as putting "#myParam" in your SQL. Then, each time you save, QueryFirst generates the C# wrapper for your query. Your parameters pop up, strongly typed, as arguments to the Execute() methods. Your results are returned in an IEnumerable or List of strongly typed POCOs, the types generated from the actual schema returned by your query. If your query doesn't run, your app won't compile. If your db schema changes and your query runs but some columns disappear, the compile error points to the line in your code that tries to access the missing data. And there are numerous other advantages. Why would you want to access data any other way?
In Sql when any word contain # sign it means it is variable and we use this variable to set value in it and use it on number area on the same sql script because it is only restricted on the single script while you can declare lot of variables of same type and name on many script. We use this variable in stored procedure lot because stored procedure are pre-compiled queries and we can pass values in these variable from script, desktop and websites for further information read Declare Local Variable, Sql Stored Procedure and sql injections.
Also read Protect from sql injection it will guide how you can protect your database.
Hope it help you to understand also any question comment me.
Old post but wanted to ensure newcomers are aware of Stored procedures.
My 10¢ worth here is that if you are able to write your SQL statement as a stored procedure, that in my view is the optimum approach. I ALWAYS use stored procs and never loop through records in my main code. For Example: SQL Table > SQL Stored Procedures > IIS/Dot.NET > Class.
When you use stored procedures, you can restrict the user to EXECUTE permission only, thus reducing security risks.
Your stored procedure is inherently paramerised, and you can specify input and output parameters.
The stored procedure (if it returns data via SELECT statement) can be accessed and read in the exact same way as you would a regular SELECT statement in your code.
It also runs faster as it is compiled on the SQL Server.
Did I also mention you can do multiple steps, e.g. update a table, check values on another DB server, and then once finally finished, return data to the client, all on the same server, and no interaction with the client. So this is MUCH faster than coding this logic in your code.
Other answers cover why parameters are important, but there is a downside! In .net, there are several methods for creating parameters (Add, AddWithValue), but they all require you to worry, needlessly, about the parameter name, and they all reduce the readability of the SQL in the code. Right when you're trying to meditate on the SQL, you need to hunt around above or below to see what value has been used in the parameter.
I humbly claim my little SqlBuilder class is the most elegant way to write parameterized queries. Your code will look like this...
C#
var bldr = new SqlBuilder( myCommand );
bldr.Append("SELECT * FROM CUSTOMERS WHERE ID = ").Value(myId);
//or
bldr.Append("SELECT * FROM CUSTOMERS WHERE NAME LIKE ").FuzzyValue(myName);
myCommand.CommandText = bldr.ToString();
Your code will be shorter and much more readable. You don't even need extra lines, and, when you're reading back, you don't need to hunt around for the value of parameters. The class you need is here...
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SqlClient;
public class SqlBuilder
{
private StringBuilder _rq;
private SqlCommand _cmd;
private int _seq;
public SqlBuilder(SqlCommand cmd)
{
_rq = new StringBuilder();
_cmd = cmd;
_seq = 0;
}
public SqlBuilder Append(String str)
{
_rq.Append(str);
return this;
}
public SqlBuilder Value(Object value)
{
string paramName = "#SqlBuilderParam" + _seq++;
_rq.Append(paramName);
_cmd.Parameters.AddWithValue(paramName, value);
return this;
}
public SqlBuilder FuzzyValue(Object value)
{
string paramName = "#SqlBuilderParam" + _seq++;
_rq.Append("'%' + " + paramName + " + '%'");
_cmd.Parameters.AddWithValue(paramName, value);
return this;
}
public override string ToString()
{
return _rq.ToString();
}
}
I've recently started working at a company that was wide open to SQL injection attacks. As in they had next to no input sanitation at all.
After pointing out the problem, I've been tasked with fixing it.
Usually this would be rather easy, replacing bare variables with SQLParamater objects.
However I've found some slightly strange code usage that got me wondering.
It seems that my predecessor had been using both stored procedures and some SQL residing in code. However in one place he seems to be combining the two.
He is dynamically building SQL using some bare variables and then passing this generated SQL to a stored procedure as a parameter.
I was wondering about the security of this, would passing actual SQL through as a parameter sanitize it or will I have to re-engineer the stored procedure?
Here is a (vastly simplified) snippet of what he was doing:
DataSet ExecuteQuery(string unsanitizedInput)
{
string dynamicSQL = "WHERE column = " + unsanitizedInput;
MySqlParameter param = new MySqlParameter("param1", dynamicSQL);
string procname = "StoredProc_Name";
DataSet ds = new DataSet();
using (MySql.Data.MySqlClient.MySqlDataAdapter adapter = new MySql.Data.MySqlClient.MySqlDataAdapter(procname, DataUtils.ConnectionStrings["string"]))
{
adapter.SelectCommand.CommandType = CommandType.StoredProcedure;
adapter.SelectCommand.Parameters.Add(param);
adapter.Fill(ds);
}
return(ds);
}
Obviously the actual query is far more complicated with many parameters. But this should give you the principal of what what he was doing.
My question is this: Is the above secure?
Does the unsanitized input get sanitized even when part of a far larger SQL statement that is to be injected into a stored procedure?
I know that the above is terrible practice and makes for some nigh impossible to figure out SQL queries but this is where I am right now.
All advice is appriciated and thanks in advance.
Query with parameters not provide a full protection against slq injection attacks, neither store procedures. I used both, but in 2010 by site's db was seriously harmed by two-step sql injection.
MSDN strongly recommends to check any input text for suspicious elements. See more How To: Protect From SQL Injection in ASP.NET.
I used the following simple code to detect the sql injection (constructed using some good sources I already cannot recall):
public static bool DetectSqlInjection(string Text)
{
string CleanText = Text.ToUpper().Replace("/**/", " ").Replace("+", " ").Replace(" ", " ");
string[] InjectionPatterns = {
"VARCHAR",
"EXEC",
"DECLARE",
"SELECT *",
"SELECT PASSWORD",
"SELECT USERNAME",
"$_GET",
"NULL OR",
"UNION ALL SELECT",
"WAITFOR DELAY",
"SELECT pg_sleep",
"SHOW TABLES FROM"
};
foreach (string Pattern in InjectionPatterns)
{
if (CleanText.Contains(Pattern))
return true;
}
return false;
}
I am struggling with proper parameter passing to a MySQL query. In MySQL workbench, my query works fine, but not in the C# code. I assume it is due to wrong parameter passing.
That's why I'd like to see what precisely do I pass to the cmd.ExecuteScalar() method. But I can't figure out how to determine the cmd string.
In debugger I only get query with formal parameters, not passed ones. And even by using cmd.ToString() I get this nonsense:
MySql.Data.MySqlClient.MySqlCommand.
Here is my code:
string timeStampStr = timeStamp.ToString("yyyy-MM-dd hh:mm:ss");
...
MySqlCommand cmd = new MySqlCommand("SELECT COUNT(*) FROM plc WHERE plc.last_communication < #timeThreshold AND plc.id = #plcId", _conn);
cmd.Parameters.AddWithValue("#timeThreshold", timeStampStr); // Is this correct ? timeStampStr is a string
cmd.Parameters.AddWithValue("#plcId", plcId);
object result = cmd.ExecuteScalar();
Thank you !
Your best bet is probably to enable the query log on MySQL and use that to profile what was sent to the database engine.
This is because the application code doesn't actually replace the placeholders with the parameter values, the database engine does. The application code invokes the parameterized query and supplies the parameters simultaneously. (As a bit of a side-effect, this allows database engines to cache execution plans for parameterized queries much more effectively, since the query itself doesn't change. This provides a slight performance improvement when using parameterized queries over concatenated values.)
And even by using cmd.ToString() I get this nonsence: MySql.Data.MySqlClient.MySqlCommand.
That's not nonsense, that's the name of the class on which you're calling .ToString(). The default behavior of .ToString() for reference types is to return the name of the type, unless you override it.
This question already has answers here:
How does SQLParameter prevent SQL Injection?
(4 answers)
Closed 8 years ago.
I hope this is the right place to ask, how does parameters.addwithvalue work? I am thinking in a way to protect against SQL injection? I have been looking quite a lot on Stackoverflow, and a lot of people say "//Against sql injection". I have been using it blindly, but now that I have to hand in a paper about my assignment I need to explain why it is protection. I have been trying to find something on MSDN, found this one:
SQL injection But it uses the parameters.add. I then read that they replace .Add with .AddWithValue, is that true? Any official on this then?
So basically, anyone better in searching for some official paperwork that it protect against SQL injection? Or can tell me how it works?
I am not trying to make you do my work, I just can't find it my self.
I am using it like this:
using (SqlConnection conn = new SqlConnection(connectionString))
using (var cmd = conn.CreateCommand())
{
conn.Open();
String queryString = "DELETE FROM dbo.SecurityAccess WHERE Username = ' #Username ";
cmd.CommandText = queryString;
cmd.Parameters.AddWithValue("#Username", Username);
cmd.ExecuteNonQuery();
}
From SQL Injection point of view using parameters is usually safe (subject to what you do with those parameters in the SQL...). Your example is safe. How one adds the parameters makes no difference from the SQL Ibjection point of view, but makes a lot of difference from ADO.Net and SQL performance point of view. AddWithValue is an anti-pattern because of performance problems related to parameter type and size. In your example the #UserName will be a parameter of type NVARCHAR, which will likely make the WHERE Username=#UserName predicate unsarg-able (will not use an index on Username). The execution result would be dreadful.
A potential solution to the datatype conversion is to use the explicit Add method instead of AddWithValue, which takes the datatype as second parameter. More details on this here.
For more details I urge you to read How Data Access Code Affects Database Performance.
In Short parameters allow for type safe and length checks on the data. Enabling a defense against SQL injection, they do not prohibit SQL injection completely you still need to check your inputs.
SO Answer on similar topic.
Good article explaining how parameters do not prevent SQL injection 100%
SQL Injection Example (Taken from MSDN:)
Consider what happens when a user types the following string in the SSN text box, which is expecting a Social Security number of the form nnn-nn-nnnn.
' ; DROP DATABASE pubs --
Using the input, the application executes the following dynamic SQL statement or stored procedure, which internally executes a similar SQL statement.
// Use dynamic SQL
SqlDataAdapter myCommand = new SqlDataAdapter(
"SELECT au_lname, au_fname FROM authors WHERE au_id = '" +
SSN.Text + "'", myConnection);
// Use stored procedures
SqlDataAdapter myCommand = new SqlDataAdapter(
"LoginStoredProcedure '" +
SSN.Text + "'", myConnection);
The developer's intention was that when the code runs, it inserts the user's input and generates a SQL the following statement.
SELECT au_lname, au_fname FROM authors WHERE au_id = '172-32-9999'
However, the code inserts the user's malicious input and generates the following query.
SELECT au_lname, au_fname FROM authors WHERE au_id = ''; DROP DATABASE pubs --'
Common ways to avoid Injection attacks.
•Constrain and sanitize input data. Check for known good data by validating for type, length, format, and range.
•Use type-safe SQL parameters for data access. You can use these parameters with stored procedures or dynamically constructed SQL command strings. Parameter collections such as SqlParameterCollection provide type checking and length validation. If you use a parameters collection, input is treated as a literal value, and SQL Server does not treat it as executable code. An additional benefit of using a parameters collection is that you can enforce type and length checks. Values outside of the range trigger an exception. This is a good example of defense in depth.
•Use an account that has restricted permissions in the database. Ideally, you should only grant execute permissions to selected stored procedures in the database and provide no direct table access.
•Avoid disclosing database error information. In the event of database errors, make sure you do not disclose detailed error messages to the user.
if you do not use Parameterised queries with above command then it looks like :
string queryString="DELETE FROM dbo.SecurityAccess WHERE Username = '"+txtUserName.Text+"'";
in the above command username would be assigned whatever user enters in TextBox( ex: txtUserName).
if user wants to inject some behaviour( adding delete/update or whatever he wants to do) he can enter following in TextBox (txtUserName)
=> "'';delete * from users"
then the above command with given username value looks like this:
string queryString="DELETE FROM dbo.SecurityAccess WHERE Username = '';delete * from users";
finally the above command would delete all the records from the users table.
I know there have been numerous questions here about inline sql vs stored procedures...
I don't want to start another one like that! This one is about inline (or dynamic) sql.
I also know this point has become more or less moot with Linq to SQL and its successor Entity Framework.
But... suppose you have chosen (or are required by your superiors) to work with plain old ADO.NET and inline (or dynamic) sql. What are then the best practices for this and for formatting the sql?
What I do now is the following:
I like to create my SQL statements in a stored procedure first. This gives me syntax coloring in SQL Server Management Studio and the ability to test the query easily without having to execute it in code through the application I'm developing.
So as long as I'm implementing/debugging, my code looks like this:
using (SqlConnection conn = new SqlConnection("myDbConnectionString"))
{
conn.Open();
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "myStoredProcName";
// add parameters here
using (SqlDataReader rd = cmd.ExecuteReader())
{
// read data and fill object graph
}
}
}
Once the debugging and testing phase is done, I change the code above like this:
using (SqlConnection conn = new SqlConnection("myDbConnectionString"))
{
conn.Open();
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandType = CommandType.Text;
cmd.CommandText = GetQuery();
// add parameters here
using (SqlDataReader rd = cmd.ExecuteReader())
{
// read data and fill object graph
}
}
}
And I add an extra private method e.g. GetQuery() in which I copy/paste the whole block of the stored procedure like this:
private string GetQuery()
{
return #"
SET NOCOUNT ON;
SELECT col1, col2 from tableX where id = #id
-- more sql here
";
}
Working like this has the benefit that I can revert the code easily to call the stored procedure again if I have to debug/update the sql code later, and once it's done I can easily put the sql code back with copy/paste, without having to put quotes around every line and stuff like that.
Is it good practice to include newlines in the query?
Are there other things or tricks that I haven't thought of which can make this approach better?
How do you guys do things like this?
Or am I the only one who still uses (has to use) inline sql?
Inline (with or without the literal #"..." syntax) is fine for short queries... but for anything longer, consider having the tsql as a file in the project; either as embedded resources / resx, or as flat files. Of course, by that stage, you should probably make it a stored procedure anyway ;-p
But having it as a separate file forces the same separation that will make it a breeze to turn into a stored procedure later (probably just adding CREATE PROC etc).
One issue with inline - it makes it so tempting for somebody to concatenate user input... which is obviously bad (you've correctly used parameters in the example).
I've used .NET resource files in the past. These were handy for keeping a library of all queries used in a particular code library, particularly when the same query might be used in multiple places (yes, I realize this also indicates some poor design, but sometimes you need to work within the box given to you).
Beyond non-trival single-line SQL statements, I always take advantage to multi-line and make it a const
const string SelectMyTable = #"
SELECT column_one
, column_two
, column_three
FROM my_table
";
This all allows me to cut and paste to SQL manager for testing.