I had expected that dapper-dot-net could replace the table name in a query like this:
connection.Query("SELECT * FROM #Table WHERE [Id] = #Id", new {Table = tb, Id = id});
However, it seems to not replace the table name. Is that an expected limitation?
With the single exception of "in" (where dapper offers some voodoo), dapper is a direct ADO.NET tool - it doesn't change the query. So the real question is: can you parameterize a table name in SQL? In every database I know of: no you cannot - so that is not valid. Dapper doesn't attempt to solve that issue.
Perhaps consider string.Format, remembering:
to white-list the legal table-names to prevent SQL injection
to use the full [square brackets] notation around the table name to allow the full range of possible names
Related
I can search customers table without any problems by SQL.
select Name
from Customers
where Name COLLATE Latin1_General_CI_AI like '%ozgur%'
This query can find "özgür"
When I place this table to cache and try to search this table with linq, I can't find "özgür" by "ozgur" search word.
Is there any similar way to use Latin1_General_CI_AI in C# LINQ?
The only place I've found that uses a collation is Entity SQL's ORDER BY clause.
You could use SqlQuery as shown here to use a SQL string (with parameters of course) that uses the COLLATE clause :
var query = "select Name from Customers " +
" where Name COLLATE Turkish_CI_AI like #name";
var results = myContext.Customers
.SqlQuery(query,new SqlParameter("#name","%ozgur%"))
.ToList();
I'd advise caution though. LIKE '%...%' can't benefit from any indexes that cover the name field and will have to search the entire table. Even Name = #name COLLATE ... may not use any indexes the collation doesn't match the collation the index was built with.
You should consider using full text search indexes and make full text search queries for specific words, eg:
SELECT Name from Customers WHERE CONTAINS(Name ,#thatName)
Update
Another option is to use an interceptor to change the SQL generated by a clause, as shown in this SO question. That interceptor uses a regular expression to replace LIKE with CONTAINS. A simpler expression could be used to inject the COLLATE clause before LIKE
The code isn't trivial, but at least it's an option.
Why don't you use following filer clause for unicode values
Converting the collation type will cause performance issues and prevent index usage
select Name
from Customers
where Name like N'%özgür%'
You can solve this by using a normal query (via context.Database.SqlQuery) that returns an array of ids and use this ids in your linq statement.
I don't know if this is really needed... but I would like write as robust code as possible, so:
What SqlDbType should be used when creating a table? SqlDbType.NChar? Or would there be a problem with a Unicode table name? Or perhaps one of the Var types because the length is unknown? I'm used to thinking about these types in the context of a database row, not table, so I'm not sure what should be used here.
EDIT
For example, a line like:
sqlCommand.Parameters.Add(new SqlParameter(parameterName,SqlDbType.NChar){ Value = value });
for a CREATE TABLE command.
You can't parameterize your table name or column names or any other database objects. You can only parameterize your values.
You can still using string concatenation it but getting your table name as an input is too risky in my opinion. You should either perform very stringent validation on the table name before putting it into the SQL, or have a white-listed set of valid table names, in order to avoid SQL Injection attacks.
Other than that, parameterized statements is only for DML Statements not DDL statements.
All object names in SQL Server are of sysname datatype. Don't know if the SqlDbType contains sysname, but it is functionally identical to nvarchar(128), so you can use this.
I have the following code:
string strTruncateTable = "TRUNCATE TABLE #TableNameTruncate";
SqlCommand truncateTable = new SqlCommand(strTruncateTable, myConnection);
truncateTable.Parameters.AddWithValue("TableNameTruncate", tbTableName.Text);
truncateTable.ExecuteNonQuery();
Whenever I run the application, I get the following error:
Incorrect syntax near '#TableNameTruncate'
How can I fix the issue?
How can I fix the issue?
By specifying the table name as part of the SQL. Table and column names can't be parameterized in most database SQL dialects, including SQL Server.
You should either perform very stringent validation on the table name before putting it into the SQL, or have a whitelisted set of valid table names, in order to avoid SQL injection attacks in the normal way.
You can only parameterized your values, not your column names or table names no matter you use DML statements or DDL statements.
And by the way, parameters are supported for Data manipulation language operations not Data Manipulation language operations.
Data manipulation language =
SELECT ... FROM ... WHERE ...
INSERT INTO ... VALUES ...
UPDATE ... SET ... WHERE ...
DELETE FROM ... WHERE ...
TRUNCATE TABLE is a Data Definition Language statement. That's why you can't use TRUNCATE TABLE with parameters even only if you try to parameter a value. You need to specify it as a part of SQL query.
You might need to take a look at the term called Dynamic SQL
As mentioned by Jon Skeet, table name cannot be parametrized for truncate operation.
To fix this issue, fully qualified query needed to be written.
So you can put a conditional check by the parameter value #TableNameTruncate and using if or switch case statement create fully qualified query then execute it.
or simply
string strTruncateTable = "TRUNCATE TABLE " + TableNameTruncate.Value;
SqlCommand truncateTable = new SqlCommand(strTruncateTable, myConnection);
truncateTable.Parameters.AddWithValue("TableNameTruncate", tbTableName.Text);
truncateTable.ExecuteNonQuery();
My question is generally we write the following through code while we are inserting data to a table
insert into tblname values('"+txt.text+"','"+txt1.text+"');
As we pass the data form the text boxes like that is it possible to insert in to table with out using table name directlty
Well you obviously need to know what table to insert into, so there has to be a table name identified to the INSERT statement. The options include:
an INSERT statement with actual table name as per your existing example
an INSERT statement with a synonym as the target (alias for an actual table - see: http://blog.sqlauthority.com/2008/01/07/sql-server-2005-introduction-and-explanation-to-synonym-helpful-t-sql-feature-for-developer/)
an INSERT statement with an updateable view as the target
a sproc call whereby the sproc knows the table to INSERT into (but the calling code does not need to know)
You should also be aware of SQL injection risks with your example - avoid concatenating values directly into a SQL string to execute. Instead, parameterise the SQL.
If you need to dynamically specify the table to insert into at run time, you have to concatenate the table name into the SQL statement you then execute. However, be very wary of SQL injection - make sure you fully validate the tablename to make sure there are no nasties in it. You could even check it is a real table by checking for it in sys.tables.
Not possible without name of table.
But you can make use of Linq To SQL (i.e any ORM) or DataAdapter.Update if you have filled it with the proper table....
You cannot do that without the table name, no. However, the bigger problem is that your code is horribly dangerous and at rick from SQL injection. You should fix this right now, today, immediately. Injection, even for internal apps, is the single biggest risk. Better code would be:
insert into tblname (Foo, Bar) values(#foo, #bar)
adding the parameters #foo and #bar to your command (obviously, replace with sensible names).
Before you ask: no, the table name cannot be parameterised; you cannot use
insert into #tblname -- blah
The table name(s) is(/are) fundamental in any query or operation.
I suppose that if it's possible you have to use parameters.
Here you have a little example.
public static bool TruncateTable(string dbAlias, string tableName)
{
string sqlStatement = string.Format("TRUNCATE TABLE {0}", tableName);
return ExecuteNonQuery(dbAlias, sqlStatement) > 0;
}
The most common recommendation to fight SQL injection is to use an SQL query parameter (several people on this thread have suggested it).
This is the wrong answer in this case. You can't use an SQL query parameter for a table name in a DDL statement.
SQL query parameters can be used only in place of a literal value in an SQL expression. This is standard in every implementation of SQL.
My recommendation for protecting against SQL injection when you have a table name is to validate the input string against a list of known table names.
You can get a list of valid table names from the INFORMATION_SCHEMA:
SELECT table_name
FROM INFORMATION_SCHEMA.Tables
WHERE table_type = 'BASE TABLE'
AND table_name = #tableName
Now you can pass your input variable to this query as an SQL parameter. If the query returns no rows, you know that the input is not valid to use as a table. If the query returns a row, it matched, so you have more assurance you can use it safely.
You could also validate the table name against a list of specific tables you define as okay for your app to truncate, as #John Buchanan suggests.
Even after validating that tableName exists as a table name in your RDBMS, I would also suggest delimiting the table name, just in case you use table names with spaces or special characters. In Microsoft SQL Server, the default identifier delimiters are square brackets:
string sqlStatement = string.Format("TRUNCATE TABLE [{0}]", tableName);
Now you're only at risk for SQL injection if tableName matches a real table, and you actually use square brackets in the names of your tables!
As far as I know, you can't use parameterized queries to perform DDL statements/ specify table names, at least not in Oracle or Sql Server. What I would do, if I had to have a crazy TruncateTable function, that had to be safe from sql injection would be to make a stored procedure that checks that the input is a table that is safe to truncate.
-- Sql Server specific!
CREATE TABLE TruncableTables (TableName varchar(50))
Insert into TruncableTables values ('MyTable')
go
CREATE PROCEDURE MyTrunc #tableName varchar(50)
AS
BEGIN
declare #IsValidTable int
declare #SqlString nvarchar(50)
select #IsValidTable = Count(*) from TruncableTables where TableName = #tableName
if #IsValidTable > 0
begin
select #SqlString = 'truncate table ' + #tableName
EXECUTE sp_executesql #SqlString
end
END
If you're allowing user-defined input to creep into this function via the tablename variable, I don't think SQL Injection is your only problem.
A better option would be to run this command via its own secure connection and give it no SELECT rights at all. All TRUNCATE needs to run is the ALTER TABLE permission. If you're on SQL 2005 upwards, you could also try using a stored procedure with EXECUTE AS inside.
CREATE OR REPLACE PROCEDURE truncate(ptbl_name IN VARCHAR2) IS
stmt VARCHAR2(100);
BEGIN
stmt := 'TRUNCATE TABLE '||DBMS_ASSERT.SIMPLE_SQL_NAME(ptbl_name);
dbms_output.put_line('<'||stmt||'>');
EXECUTE IMMEDIATE stmt;
END;
Use a stored procedure. Any decent db library (MS Enterprise Library is what I use) will handle escaping string parameters correctly.
Also, re:parameterized queries: I prefer to NOT have to redeploy my app to fix a db issue. Storing queries as literal strings in your source increases maintenance complexity.
Have a look at this link
Does this code prevent SQL injection?
Remove the unwanted from the tableName string.
I do not think you can use param query for a table name.
There are some other posts which will help with the SQL injection, so I'll upvote those, but another thing to consider is how you will be handling permissions for this. If you're granting users db+owner or db_ddladmin roles so that they can truncate tables then simply avoiding standard SQL injection attacks isn't sufficient. A hacker can send in other table names which might be valid, but which you wouldn't want truncated.
If you're giving ALTER TABLE permissions to the users on the specific tables that you will allow to be truncated then you're in a bit better shape, but it's still more than I like to allow in a normal environment.
Usually TRUNCATE TABLE isn't used in normal day-to-day application use. It's used for ETL scenarios or during database maintenance. The only situation where I might imagine it would be used in a front-facing application would be if you allowed users to load a table which is specific for that user for loading purposes, but even then I would probably use a different solution.
Of course, without knowing the specifics around why you're using it, I can't categorically say that you should redesign, but if I got a request for this as a DBA I'd be asking the developer a lot of questions.
Use parameterized queries.
In this concrete example you need protection from SQL injection only if table name comes from external source.
Why would you ever allow this to happen?
If you are allowing some external entity (end user, other system, what?)
to name a table to be dropped, why won't you just give them admin rights.
If you are creating and removing tables to provide some functionality for end user,
don't let them provide names for database objects directly.
Apart from SQL injection, you'll have problems with name clashes etc.
Instead generate real table names yourself (e.g DYNTABLE_00001, DYNTABLE_00002, ...) and keep a table that connects them to the names provided by user.
Some notes on generating dynamic SQL for DDL operations:
In most RDBMS-s you'll have to use dynamic SQL and insert table names as text.
Be extra careful.
Use quoted identifiers ([] in MS SQL Server, "" in all ANSI compliant RDBMS).
This will make avoiding errors caused by invalid names easier.
Do it in stored procedures and check if all referenced objects are valid.
Do not do anything irreversible. E.g. don't drop tables automatically.
You can flag them to be dropped and e-mail your DBA.
She'll drop them after the backup.
Avoid it if you can. If you can't, do what you can to minimize rights to other
(non-dynamic) tables that normal users will have.
You could use SQLParameter to pass in tableName value. As far as I know and tested, SQLParameter takes care of all parameter checking and thus disables possibility of injection.
If you can't use parameterized queries (and you should) ... a simple replace of all instances of ' with '' should work.
string sqlStatement = string.Format("TRUNCATE TABLE {0}", tableName.Replace("'", "''"));