Parameter Binding: What happens under the hood? - c#

.NET, Java and other high level database API's in various language often provide techniques known as prepared statements and parameter binding as opposed to sending plain text commands to the Database server. What I would like to know is what happens when you execute a statement like this:
SqlCommand cmd = new SqlCommand("GetMemberByID");
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter param = new SqlParameter("#ID", memberID);
para.DbType = DbType.Integer;
cmd.Parameters.Add(param);
I know this is a best practice. SQL injection attacks are minimized this way. But what exactly happens under the hood when you execute these statements? Is the end result still a SQL safe string? If not, what is the end result? And is this enough to prevent SQL injection attacks?

The MySQL manual page on prepared statements provides lots of information (which should apply to any other RDBMS).
Basically, your statement is parsed and processed ahead of time, and the parameters are sent separately instead of being handled along with the SQL code. This eliminates SQL-injection attacks because the SQL is parsed before the parameters are even set.

in layman terms: if a prepared statement is sent then the DB will use a plan if it is available, it doesn't not have to recreate a plan every time this query is sent over but only the values of the params have changed. this is very similar to how procs work, the additional benefit with procs is that you can give permission through procs only and not to the underlying tables at all

If you're using MS SQL, load up the profiler and you'll see what SQL statements are generated when you use parameterised queries. Here's an example (I'm using Enterprise Libary 3.1, but the results are the same using SqlParameters directly) against SQL Server 2005:
string sql = "SELECT * FROM tblDomains WHERE DomainName = #DomName AND DomainID = #Did";
Database db = DatabaseFactory.CreateDatabase();
using(DbCommand cmd = db.GetSqlStringCommand(sql))
{
db.AddInParameter(cmd, "DomName", DbType.String, "xxxxx.net");
db.AddInParameter(cmd, "Did", DbType.Int32, 500204);
DataSet ds = db.ExecuteDataSet(cmd);
}
This generates:
exec sp[underscore]executesql N'SELECT * FROM tblDomains WHERE DomainName = #DomName AND DomainID = #Did',
N'#DomName nvarchar(9),
#Did int',
#DomName=N'xxxxx.net',
#Did=500204
You can also see here, if quotation characters were passed as parameters, they are escaped accordingly:
db.AddInParameter(cmd, "DomName", DbType.String, "'xxxxx.net");
exec sp[underscore]executesql N'SELECT * FROM tblDomains WHERE DomainName = #DomName AND DomainID = #Did',
N'#DomName nvarchar(10),
#Did int',
#DomName=N'''xxxxx.net',
#Did=500204

Related

How to specify SQL column alias as SqlParameter?

Is it possible to add the alias of a column as an SqlParameter to an SQL command? If so, how is it specified?
As a simplified example, say I have an SQL command that is constructed like this:
SqlCommand GetCommand(string columnName)
{
string filter = String.Format("SELECT MyColumn1 AS '{0}' FROM MyTable", columnName);
return new SqlCommand(filter);
}
This command does nothing to prevent an SQL Injection attack, so I want to follow the standard procedure and parameterize the command.
I'm used to converting statements in the WHERE clause to use parameters. The statements look similar to the above, for example:
SqlCommand command("SELECT * FROM MyTable WHERE name = '{0}'", name);
When I convert this, it becomes:
SqlCommand command("SELECT * FROM MyTable WHERE name = #name");
command.Parameters.Add(new SqlParameter("name", SqlDbType.NVarChar) { Value = name });
That works well. Taking the same approach here with the GetCommand() method gives:
SqlCommand GetCommand(string columnName)
{
string filter = "SELECT MyColumn1 AS #columnName FROM MyTable";
SqlCommand command = new SqlCommand(filter);
command.Parameters.Add(new SqlParameter("columnName", SqlDbType.NVarChar)
{ Value = columnName });
return command;
}
But, when the command is executed, it results in:
An exception of type 'System.Data.SqlClient.SqlException' occurred in MyApplication.exe but was not handled in user code
Additional information: Incorrect syntax near '#columnName'.
I see there are plenty of questions on SO and the web in general about use of SqlParameter, but seemingly none that touch on their use with column aliases.
There's no indication in Microsoft's SqlParameter documention either. From this, I noticed that the SqlParameter.Direction property defaults to ParameterDirection.Input; the column alias is used in output, so I tried InputOutput and Output, but it made no difference to the results.
Short answer: you can't.
Column Aliases are not parameterizable. They are identifiers in the SQL language, not values - just like the column name itself, or the table name.
"Get me column X from table Y and name it Z in the result set." None of X, Y or Z are parameterizable.
Note that this is not a limitation of SqlParameter but of the SQL language as implemented by Sql Server.
Parameters are not designed for aliasing TSQL columns. If you need an alias, just give it one in the TSQL. Additionally, the In/Out aspect of the parameter is for cases where the query modifies the parameter during running. Such as an output parameter of a stored procedure.
In truth, what it appears you're trying to do is get a dataset where the returned column name is based upon an inputted value.
I would use a data adapter to fill a data table, and then just rename the column to the desired value.
dataTable.Columns["MyColumn1"].ColumnName = columnName;
Strange thing to do, but you can build some sql with the parameter and then exec it.
Declare #sql VarChar(255)
Set #sql = 'SELECT ClientNumber AS ' + #columnName + ' FROM Ib01'
Exec(#sql)
You can't parameterize schema names and aliases. If you must have dynamic aliases, you'll need to protect yourself from SQL injection in the application layer.
Consider creating a whitelist of valid aliases, and only select from the whitelist.
If the alias comes from user input, you'll have to validate/sanitize the input.
Edit: It's a bad practice to rely on the application layer to prevent SQL injection attacks. But sometimes business drivers or other reasons force this to happen. My suggestions here are ways to mitigate the risk of SQL injection if you are forced to do this.

Entering data with a ' (apostrophy) into SQL Server CE table

How could I go about entering data such as "John's shoe" into a SQL Server CE table (version 3.5) as the insert statements and so forth do not accept the use of the ' apostrophe in a statement such as the following statement:
INSERT INTO ShowsDB(Item) VALUES('+ "John's shoes" + "')
You must avoid putting your data directly into your SQL, basically. Use parameterized SQL instead:
// I'm assuming you're opening the connection already
string sql = "INSERT INTO ShowDB(ITEM) VALUES (#Name)";
using (var command = new SqlCommand(sql, connection))
{
command.Parameters.Add("#Name", SqlDbType.NVarChar).Value = "John's shoes";
command.ExecuteNonQuery();
}
Using parameterized SQL has three benefits:
Avoids SQL injection attacks
Avoids unnecessary and dangerous string conversions (particularly for date/time types)
Separates the "code" (SQL) from the data (parameters) which makes it easier to understand
Standard SQL escaping is that quotes should be doubled, so your query becomes
INSERT INTO ShowsDB(Item) VALUES('+ "John''s shoes" + "')
Which is perfectly fine for things like running SELECT statements against a copy of the DB to diagnose problems, but should NEVER be used in actual production systems. Parameterized queries are your friend.

how to prevent SQL Injection in a asp.net website

For email entry in a text box by the user i am doing client side check, to find whether the email is valid or not
string emailexist = "SELECT COUNT(DISTINCT UserID) as count FROM tbl_user WHERE Email=#Email ";
<asp:RegularExpressionValidator ID="RegularExpressionValidator2" ValidationGroup="Login" ControlToValidate="txtUserName"
ValidationExpression="\w+([-+.]\w+)*#\w+([-.]\w+)*\.\w+([-.]\w+)*" CssClass="Error"
runat="server" />
is this regular expression good enough to prevent sql injection for email.
Other Text:
string groupExistQuery = "SELECT COUNT(DISTINCT GroupID) as count FROM tbl_group WHERE GroupName=#GroupName";
I am doing a query in server side to check whether the group name entered by the user is already available in the database, there is a strong possibility to perform sql injection here. How should I prevent from it.
A regex is unrelated to SQL injection (blacklisting etc is never the strongest approach); however, the use of the parameter #Email means (assuming it remains parameterised) that is not susceptible to SQL injection.
SQL injection relates to inappropriate concatenation of input; the main tool to fight it is parameters, which has already happened here.
For example, if you did:
var sql = "SELECT ...snip... WHERE Email='" + email + "'"; // BAD!!!!!
then that is heavily susceptible to SQL injection. By using a parameter, the value is not treated as part of the query, so the attacker does not have at attack vector.
If you use parameterised values, you are going to be fine regardless, you can not inject via parameters, only via concatenated values.
You can prevent it by not using Direct SQL and using parameterised queries and/or Stored Procedures instead.
Use parameterised values
Encode your strings
Here is the reply from Microsoft Pattern & Practices group to your question.
In general, the simple rule is: not to use dynamic SQL generation and if you do, sanitize your input.
Never just concatenate strings for building your SQL query. If you need to build a query on your own in your application, then use parametrized SQL queries with parameters -- this way you are on a safe side.
Here is an example from the document I provide the link to above:
DataSet userDataset = new DataSet();
SqlDataAdapter myCommand = new SqlDataAdapter(
"LoginStoredProcedure", connection);
myCommand.SelectCommand.CommandType = CommandType.StoredProcedure;
myCommand.SelectCommand.Parameters.Add("#au_id", SqlDbType.VarChar, 11);
myCommand.SelectCommand.Parameters["#au_id"].Value = SSN.Text;
myCommand.Fill(userDataset);

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.

C# SqlCommand - cannot use parameters for column names, how to resolve?

Is there any way how to do that? This does not work:
SqlCommand command = new SqlCommand("SELECT #slot FROM Users WHERE name=#name; ");
prikaz.Parameters.AddWithValue("name", name);
prikaz.Parameters.AddWithValue("slot", slot);
The only thing I can think of is to use SP and declare and set the variable for the column. Seems to me a bit ackward.
As has been mentioned, you cannot parameterise the fundamental query, so you will have to build the query itself at runtime. You should white-list the input of this, to prevent injection attacks, but fundamentally:
// TODO: verify that "slot" is an approved/expected value
SqlCommand command = new SqlCommand("SELECT [" + slot +
"] FROM Users WHERE name=#name; ")
prikaz.Parameters.AddWithValue("name", name);
This way #name is still parameterised etc.
You cannot do this in regular SQL - if you must have configurable column names (or table name, for that matter), you must use dynamic SQL - there is no other way to achieve this.
string sqlCommandStatement =
string.Format("SELECT {0} FROM dbo.Users WHERE name=#name", "slot");
and then use the sp_executesql stored proc in SQL Server to execute that SQL command (and specify the other parameters as needed).
Dynamic SQL has its pros and cons - read the ultimate article on The Curse and Blessings of Dynamic SQL expertly written by SQL Server MVP Erland Sommarskog.

Categories

Resources