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;
}
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();
}
}
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.
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 am trying to maintain data consistency across multiple automated services accessing a single MySQL (InnoDB) database. Currently, I am trying to accomplish this using GET_LOCK. I am working with auto-generated typed datasets, and have configured the following query:
SELECT GET_LOCK('#id', 1)
The adapter also accepts an Int32 as a parameter. The problem is that the '#id' field is interpreted as a string literal, so I cannot get a dynamically assigned lock string. My question is if this is even possible.
My current workaround is something along the lines of:
DataSetTableAdapters.myTableAdapter typedAdapter = new DataSetTableAdapters.myTableAdapter();
MySql.Data.MySqlClient.MySqlCommand selectCommand_backup = typedAdapter.Adapter.SelectCommand;
typedAdapter.Adapter.SelectCommand = new MySql.Data.MySqlClient.MySqlCommand();
typedAdapter.Adapter.SelectCommand.Connection = typedAdapter.Connection;
typedAdapter.Adapter.SelectCommand.CommandText = string.Format("SELECT GET_LOCK('{0}_{1}', 1)", tableName, id);
typedAdapter.Adapter.SelectCommand.CommandType = System.Data.CommandType.Text;
typedAdapter.Connection.Open();
typedAdapter.Adapter.SelectCommand.ExecuteScalar();
typedAdapter.Connection.Close();
typedAdapter.Adapter.SelectCommand = selectCommand_backup;
I'm also open to other ideas. I want to prevent conflict resolution if possible, since it would be challenging to handle for an automated system.
I'm using Microsoft Visual C# 2008 Express Edition with SqlLite. I'm successfully able to open my database and with C# code, add entries to my tables.
When it comes to retriving data, I'm having some issues and have been searching and searching the internet for basic tutorial information on how to do these basic things...
Here's my code... (after I've opened up a connection to the database which is called 'conn' here):
SQLiteCommand cmd = new SQLiteCommand(conn);
cmd.CommandText = "select myField1,myField2 from myTable where myField3 = '" + tempstring + "';";
cmd.CommandType = CommandType.Text;
SQLiteDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
string tmp = reader.GetString(0);
System.Console.WriteLine(" my output = " + tmp);
}
When I execute this... I get no errors and because I get no output on that last line, it looks like the while loop is not executing at all.
I'm a beginner to this stuff... what am I missing and is there a good web resource where I can learn these basic things? I'm pretty comfortable in SQL on it's own... just not integrated in C# like this...
First, remove the hurtful trailing semicolon from the line while (reader.Read());...!
This looks correct to me. Does the property reader.HasRows return true for your query?
A couple of side issues to be aware of are:
Be sure to dispose of your SQL resources by wrapping your objects in using { } blocks.
Consider using parameterized queries instead of injecting the query parameter directly in the SELECT statement.
Answering your question on how to write parameterized queries:
cmd.CommandText = "select myField1,myField2 from myTable where myField3 = #tempString;";
SQLiteParameter param = new SQLiteParameter("#tempString");
cmd.Parameters.Add(param);
// you can modify that value without touching the sql statement (which means you could cache the above command)
param.Value = tempstring;
SQLiteDataReader reader = cmd.ExecuteReader();
[...]
Parameters in SQLite can have several forms which you can find here.
See here for more info on parameterized queries.
Good one, Alex.
In addition to that and since you are beginning with sqlite (you may want to delete second L from the tag), remember that sqlite does not really guaranty data type safety on the database level.
Not to divert you from your Sqlite question, but if you are having comfort issues with Sqlite queries embedded in C#, you could try NHibernate coupled with Fluent NHibernate. These technologies provide an excellent data access mechanism into databases, including Sqlite.
NHibernate requests into Sqlite are very fast, and you won't have to worry about some of the Sqlite idiosyncrasies. If you build out your data-access layer properly with NHibernate, you should be able to up-scale to a more robust database very quickly.