I'm struggling to create a table using Npgsql.
using (NpgsqlCommand command = new NpgsqlCommand("CREATE TABLE #tableName(asdf TEXT)", con))
{
command.Parameters.Add(new NpgsqlParameter("#tableName", "test"));
command.ExecuteReader();
}
throws an exception:
Npgsql.PostgresException: '42601: syntax error at or near "$1"', which doesn't bring any clue to find out what is wrong.
How can I create a table using parameters? Is it actually possible?
Table names cannot be parameterized - you must integrate the name in your DDL string; parameterization is (among other things) about generating and reusing a single query plan regardless of the parameter's content, but that doesn't apply to CREATE TABLE statements.
If you need to create tables dynamically, you can use string interpolation, but be sure to escape properly to avoid SQL injection for user inputs.
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'm trying to set up so that the table name is passed to the command text as a parameter, but I'm not getting it to work. I've looked around a bit, and found questions like this: Parameterized Query for MySQL with C#, but I've not had any luck.
This is the relevant code (connection == the MySqlConnection containing the connection string):
public static DataSet getData(string table)
{
DataSet returnValue = new DataSet();
try
{
MySqlCommand cmd = connection.CreateCommand();
cmd.Parameters.AddWithValue("#param1", table);
cmd.CommandText = "SELECT * FROM #param1";
connection.Open();
MySqlDataAdapter adap = new MySqlDataAdapter(cmd);
adap.Fill(returnValue);
}
catch (Exception)
{
}
finally
{
if (connection.State == ConnectionState.Open)
connection.Close();
}
return returnValue;
}
If I change:
cmd.CommandText = "SELECT * FROM #param1";
to:
cmd.CommandText = "SELECT * FROM " + table;
As a way of testing, and that works (I'm writing the xml from the dataset to console to check). So I'm pretty sure the problem is just using the parameter functionality in the wrong way. Any pointers?
Also, correct me if I'm mistaken, but using the Parameter functionality should give complete protection against SQL injection, right?
You can not parameterize your table names, column names or any other databse objects. You can only parameterize your values.
You need to pass it as a string concatenation on your sql query but before you do that, I suggest use strong validation or white list (only fixed set of possible correct values).
Also, correct me if I'm mistaken, but using the Parameter
functionality should give complete protection against SQL injection,
right?
If you mean parameterized statements with "parameter functionality", yes, that's correct.
By the way, be aware, there is a concept called dynamic SQL supports SELECT * FROM #tablename but it is not recommended.
As we have seen, we can make this procedure work with help of dynamic
SQL, but it should also be clear that we gain none of the advantages
with generating that dynamic SQL in a stored procedure. You could just
as well send the dynamic SQL from the client. So, OK: 1) if the SQL
statement is very complex, you save some network traffic and you do
encapsulation. 2) As we have seen, starting with SQL 2005 there are
methods to deal with permissions. Nevertheless, this is a bad idea.
There seems to be several reasons why people want to parameterise the
table name. One camp appears to be people who are new to SQL
programming, but have experience from other languages such as C++, VB
etc where parameterisation is a good thing. Parameterising the table
name to achieve generic code and to increase maintainability seems
like good programmer virtue.
But it is just that when it comes to database objects, the old truth
does not hold. In a proper database design, each table is unique, as
it describes a unique entity. (Or at least it should!) Of course, it
is not uncommon to end up with a dozen or more look-up tables that all
have an id, a name column and some auditing columns. But they do
describe different entities, and their semblance should be regarded as
mere chance, and future requirements may make the tables more
dissimilar.
Using table's name as parameter is incorrect. Parameters in SQL just works for values not identifiers of columns or tables.
One option can be using SqlCommandBuilder Class, This will escape your table name and not vulnerable to SQL Injection:
SqlCommandBuilder cmdBuilder = new SqlCommandBuilder();
string tbName = cmdBuilder.QuoteIdentifier(tableName);
You can use the tbName in your statement because it's not vulnerable to SQL Injection now.
I have the following code:
SqlDataAdapter adapter = new SqlDataAdapter("SELECT TOP 0 * FROM [tableName]", conn);
DataTable dt = new DataTable();
adapter.FillSchema(dt, SchemaType.Mapped);
I am using this to build a DataTable of the table schema.
Normally, when people are asking about SQL injection, they are talking about query params :), my question is about the table name:
SELECT TOP 0 *
FROM [tableName]
[tableName] is actually going to be dynamic / determined at runtime (this is for a framework btw)...
The tableName passed into the method is not trusted, so I want to make sure there isn't any funny business going on?
Do I have to manually scrub the table name (and I'm sure I'll miss something)? Or is there a built in method for that? Or somehow to prevent the SQL injection on the table name?
You could just go with the rules for valid table names
128 char - letters, numbers, and limited other special characters
In those rules I don't think you could do an injection
CreateTable see table_name
ValidIdentifier
You can use the following query to get a list of all tables in the database and use that as a white list:
SELECT TABLE_NAME FROM <DATABASE_NAME>.INFORMATION_SCHEMA.Tables
WHERE TABLE_TYPE='BASE TABLE'
Replace
<DATABASE_NAME>
with your database name.
If someone attempts to input a table name which is not in that list, then don't execute the query.
Update
As for the "multiple connection strings" case, you can also use a simple query to check the current database name:
SELECT db_name()
So you should be able to easily craft a method that simply gets a list of valid table names from the current database, no matter if the connection-string/db-name is dynamic or not. And in the grand scheme of things, I doubt that these two queries are going to affect the performance of your application, like you said, you could easily cache the table list, if necessary.
The tableName passed into the method is not trusted, so I want to make
sure there isn't any funny business going on?
One method is to first execute a parameterized query, passing the table name as a parameter (nvarchar max length 128) to the QUOTENAME function:
SELECT QUOTENAME(#TableName) AS ScrubbedTableName;
The returned value can then be used in your TableAdapter query without the risk of SQL injection. However, this will not prevent disclosure of meta data if a table other than one expected is specified.
You can keep sqlDataAdapter and use
Adapter.selectcommand.parameters.add(#"whatever", value)
Edit: Sorry! I missed the part about this being related to a table name, this code doesnt work. :( I apologize.
I am using Entity Framework with PostgreSQL, which means I'm using Npgsql as the data provider. I would like to call context.Database.ExecuteSqlCommandAsync to make a query, and I'm trying to use parameters to avoid injection attacks. One example of a query I would like to make is alter table add column. Here is what my code looks like to set up the parameters and the sql query:
NpgsqlParameter tableNameParam = new NpgsqlParameter("tableName", NpgsqlDbType.Text);
tableNameParam.Value = entityTableName;
NpgsqlParameter fieldNameParam = new NpgsqlParameter("fieldName", NpgsqlDbType.Text);
fieldNameParam.Value = sqlFieldName;
NpgsqlParameter fieldTypeParam = new NpgsqlParameter("fieldType", NpgsqlDbType.Text);
fieldTypeParam.Value = sqlType;
object[] sqlParams = {tableNameParam, fieldNameParam, fieldTypeParam};
string addColumnQuery = "ALTER TABLE #tableName ADD #fieldName #fieldType";
await _context.Database.ExecuteSqlCommandAsync(addColumnQuery, sqlParams);
When I run this I catch an NpgsqlException with
error 42601: syntax error at or near \"(\"".
I looked into the stack trace and found that the ErrorSQL displays:
"ALTER TABLE (('dbo.person_entity')::text) ADD (('name')::text)(('varchar')::text)"
As you can see the query went horribly wrong. In my test I am using a person entity and adding a column "name" with type "varchar". I just want the query to be like this:
"ALTER TABLE dbo.person_entity ADD name varchar"
But for some reason using NpgsqlParameters is messing that up. I suspect it has to do with the NpgsqlDbType.Text but it seems like the NpgsqlParameter constructor requires a type as the second argument.
First, PostgreSQL doesn't support parameters for column/table names. There are some good reasons for this behavior: it doesn't normally make sense to allow users to create arbitrary fields with arbitrary types in your databases - even if you sanitize them to prevent SQL injection. Try to think of redesigning your application.
For a more technical explanation of what's happening in your case, the Npgsql Entity Framework provider replaces your parameter placeholder (e.g. #fieldName) with a text literal - and (('dbo.person_entity')::text) is a perfectly valid literal. The problem is that column names and types aren't text literals: you don't surround them with quotes.
I am working with C#. I need to write a select inline query.
The table name should be taken from config. I cannot write a stored procedure.
SqlCommand myCommand= new SqlCommand();
myCommand.CommandText = "Select * from " + tableName;
myCommand.CommandType = CommandType.Text;
myCommand.Connection = connString;
How to avoid sql injection ?
Just create a query with a real param and check for the existence of the tablename - somthing like:
SELECT COUNT(*) FROM SYS.TABLES WHERE NAME = #pYOURTABLENAME
IF that returns 1 then you know that the table exists and thus can use it in the SELECT you showed in the question...
However I strongly recommend to try anything to get rid of the need for any code prone to SQL injection!
I would ensure table name contains only these characters:
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz[]. -_0123456789
E.g.,
Regex regex = new Regex(#"^[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\[\]. -_0123456789]{1,128}$");
if (!regex.IsMatch(tableName)) throw new ApplicationException("Invalid table name");
To do a more comprehensive job including non-English languages see this reference on what a valid table names:
http://msdn.microsoft.com/en-us/library/ms175874.aspx
You need to verify that tableName is appropriate. After some sanity checking (making sure it has no spaces, or other disallowed characters for table names, etc), I would then first query the database for the names of all tables, and programmatically verify that it is one of those table names. Then proceed to run the query you show.
I'd look at moving the SQL to a stored proc and review this article by Erland Sommarskog as it has some great ideas for using dynamic SQL within stored procs. I'd certainly look into it. It discusses a lot of the issues around SQL injection and possible alternatives to dynamic SQL.
He also has another great article on ways to use arrays in stored procs. I know you didn't ask for that, but I often refer to these two articles as I think they are quite insightful and provide you with some useful ideas with regards to writing your procedures.
In addition to some of the suggestions linked above, I still have some basic parameter sanitisation mechanisms that I use if I am ever using dynamic SQL. An example of this is as follows;
IF LEN(#TableName) < 5 OR LEN(#TableDisplayName) < 5
BEGIN
RAISERROR('Please ensure table name and display name are at least 5 characters long', 16, 1)
END
IF NOT (#TableName not like '%[^A-Z]%')
BEGIN
RAISERROR('The TableName can only contain letters', 16, 1)
END
IF NOT (#TableDisplayName not like '%[^0-9A-Z ]%')
BEGIN
RAISERROR('The TableDisplayName can only contain letters, numbers or spaces', 16, 1)
END
This combined with using parameters within your dynamic sql and then executing using sp_executesql certainly help to minimise the possibility of a SQL injection attack.