Parameterise table name in .NET/SQL? - sql

As the topic suggests I wish to be able to pass table names as parameters using .NET (doesn't matter which language really) and SQL Server.
I know how to do this for values, e.g. command.Parameters.AddWithValue("whatever", whatever) using #whatever in the query to denote the parameter. The thing is I am in a situation where I wish to be able to do this with other parts of the query such as column and table names.
This is not an ideal situation but it's one I have to use, it's not really prone to SQL injection as only someone using the code can set these table names and not the end-user. It is messy however.
So, is what I am asking possible?
EDIT: To make the point about SQL injection clear, the table names are only passed in by source code, depending on the situation. It is the developer who specifies this. The developer will have access to the database layer anyway, so the reason I am asking is not so much for security but just to make the code cleaner.

You cannot directly parameterize the table name. You can do it indirectly via sp_ExecuteSQL, but you might just as well build the (parameterized) TSQL in C# (concatenating the table-name but not the other values) and send it down as a command. You get the same security model (i.e. you need explicit SELECT etc, and assuming it isn't signed etc).
Also - be sure to white-list the table name.

I don't think I've ever seen this capability in any SQL dialect I've seen, but it's not an area of expertise.
I would suggest restricting the characters to A-Z, a-z, 0-9, '.', '_' and ' ' - and then use whatever the appropriate bracketing is for the database (e.g. [] for SQL Server, I believe) to wrap round the whole thing. Then just place it directly in the SQL.
It's not entirely clear what you meant about it not being a SQL injection risk - do you mean the names will be in source code and only in source code? If so, I agree that makes things better. You may not even need to do the bracketing automatically, if you trust your developers not to be cretins (deliberately or not).

You can pass the table name as a parameter like any other parameter. the key is you have to build a dynamic sql statement, which then you should consider if it's easier to build it in your app tier or in the procs.
create procedure myProc
#tableName nvarchar(50)
as
sp_executesql N'select * from ' + #tablename
fyi this code sample is from memory have a look at BOL for the proper syntax of sp_executesql.
Also this is highly sucesptible to SQL injection as you indicated is not an issue for you but anyone reading this should be very wary of accepting input from a user to generate their queries like this.

SQL query parameters can only take the place of a literal value. You cannot use a parameter for a table name, column name, list of values, or other SQL syntax. That's standard SQL behavior across all brands of database.
The only way to make the table name dynamic is to interpolate a variable into your SQL query before you prepare that string as a statement.
BTW, you're fooling yourself if you think this isn't a risk for SQL injection. If you interpolate the table name into the query dynamically, you need to use delimited identifiers around the table name, just as you would use quotes around a string literal that is interpolated from a variable.

The idea that it is not prone to SQL injection is misguided. It may be less prone to SQL injection from front end users, but it is still very much prone to SQL injection. Most attacks on databases come from inside the company being attacked, not from end users.
Employees may have grudges, they may be dishonest, they may be disgruntled, or they may just be not so bright and think that it's ok to bypass security to do whatever it is that THEY think should be done to the database.

Please see this post answer by user Vimvq1987:
MySqlParameter as TableName
Essentially you first check the table name against the schema, in which the table name is used in a parameterized fashion. Then if all is ok, the table name is legit.
Paraphrased basic idea is:
SELECT table_name
FROM information_schema.tables
WHERE table_schema = 'databasename'
AND table_name = #table;
cmd.Parameters.AddWithValue("#table",TableName);
If this returns ok with the table name, go ahead with your main query...

I would just check
select OBJECT_ID(#tablename)
the idea is to prevent injection you know it has to be table name this was if this returns a number then i would run the actual query,

Related

How PDO prepared statements help to prevent SQL vulnerable statements?

I'm so confused or rather I'm like, soooooooooo confused with pdo prepared statements. I know that prepared statements are the best way to keep data safe from hackers.
From : How can prepared statements protect from SQL injection attacks?
We are sending program to the server first
$db->prepare("SELECT * FROM users where id=?"); where the data is
substituted by some variable called "placeholder".
Note that the very same query being sent to the server, without any
data in it! And then we're sending the data with the second request,
totally separated from the query itself:
$db->execute($data);
query-
$query=$db->prepare("SELECT * FROM USERS WHERE username=?");
$query->execute(array($tex));
$tex=blah; DROP TABLE users;--
then it will be like - SELECT * FROM USERS WHERE username=blah; DROP TABLE users;--
how prepare statements will help me with this example above?
I'm really sorry if this question is vague to understand. Any help would be appreciated. Thanks in advance.
The prepared statement handler will make sure the bound value is always used as valid SQL value/literal (ie. an SQL string or a number) and never as 'raw SQL text'1.
This is why placeholders values cannot be used as identifiers such as column or table names or act as other SQL keywords; and cannot generate the vulnerable query hypothesized. Instead it is treated as the following:
WHERE username='blah; DROP TABLE users;--'
--^ placeholder ensures valid SQL string value is used
-- (note automatic/implicit addition of SQL quotes)
And even when binding with 'more tricky' data:
$tex = "blah'; DROP TABLE users;--"; // embedded SQL quote character
It would still be safe:
WHERE username='blah''; DROP TABLE users;--'
--^ placeholder STILL ensures valid SQL string value is used
Thus, when using placeholders, it is impossible to generate the SQL that is vulnerable (in this way).
For SQL Injection the 'shape' of the query (which includes keywords and identifiers, but excludes values) must itself be altered by the input.
1 Technically placeholders values can also be sent through a separate data channel (depending on adapter/driver) and thus might not even appear in the raw SQL query itself.
However a simple way to think about why placeholders are safe, or how they 'work' is:
When using placeholders the adapter ensures that the equivalent of 'sql really safe escape' and applicable quoting is always used for every bound text value - and is thus impossible for accidentally forget.

How do I declare a variable for a hard coded database?

I have some hard coded database values in my SQL and I need to convert to variables , I have declared them in places but I need Production2 to be changed to #Source_Database_Name variable below but I dont know how to place it in with the Information Schema just after it without getting a syntax error
IF EXISTS(SELECT * FROM Production2.INFORMATION_SCHEMA.COLUMNS
I guess that the only way you can do this is dynamic sql generation (unfortunately). And there's actually quite a few reasons (from database engine's perspective) for not allowing a user to parametrise queries in a way you want. The one that sits on top of my head is that it will make impossible to validate syntax of your query (no way to know that you're referring to what actually exists).
In case you're talking about "being able to execute the same set of SQL against different database(s)" and you're actually executing this sql from code (.NET / anything), you can achieve the same result by specifying target database in connection string (i.e. by changing the level where you set database -- not in the [sql] script, but rather at some external point).

Dynamic SQL Within A Stored Procedure Security

I've got the SQL stored procedure from hell that I've created and all input parameters are parameterised for security but it's not running as quick as I'd like so I wanted to make it dynamic and so a bit more efficient.
I know I can keep my input parameters to my stored procedure, then within it create a dynamic SQL statement into which I can then pass the input parameters of the stored procedure, but are there any security implications I need to be aware of when doing this? I'm guessing not as it just another set of parameters and they should be treated the same as the parameters passed to the current stored procedure.
Obviously, producing code like this "WHERE OrderNo = ' + #orderno is asking for trouble - I will be doing 'WHERE OrderNo = #orderno' in the dynamic SQL, but is there anything else I need to be aware of?
Thx MH
PS - before anyone suggests it, I can't create the SQL dynamically at the client side using LINQ or similar - it all (for various reasons) has to be contained and controlled at the database level
There is a form of SQL injection that many people don't think about when doing dynamic SQL in stored procedures: SQL Truncation attacks.
With a SQL truncation attack, the attacker injects a long peace of text making the used text variable overflow and lose part of the query.
This article gives more information about this.
Where your parameters are always Data Items, both when being passed to the StoredProc and when used in yor DynamicSQL, everything will stay safe.
Should any of your StoredProc's parameters end up being table or field names, and so forming part of the structure of the DynamicSQL itself, you introduce a new risk : That the parameter can be used to inject rogue SQL Code.
To prevent against such an injection attack you should always validate any such parameters.
One example of how to do this would be to use the input parameter as a token, rather than substitute it directly into the DynamicSQL...
SET #SQL = #SLQ + CASE targetTable WHEN '1' THEN 'table1'
WHEN 'tx' THEN 'tableX'
END
Some people suggest you only need to validate on the client application. But that means that if someone becomes able to execute you SP's directly, the SP has become a point of attack. I always prefer to validate both on the client AND in the server.
EDIT Performance
Note that using DynamicSQL isn't always a guarnatee of performance increases. If you use parameterised queries, the execution plans can indeed be stored. But if the queries do vary greatly, you may still find a significant overhead in compiling the SQL.
There is also the fact that dependancy tracking is lost. It's not possible to see what tables the SP is dependant on, because the code is hidden away as strings.
I have very rarely found that DynamicSQL is needed. Often a complex query can be reformed as several optimised queries. Or the data can be re-structured to meet the new demands. Or even a rethink of both the data and the algorithm using the data. One might even be able to suggest that a dependancy on DynamicSQL is an indicator of another underlying problem.
Perhaps it's not in the scope of your question, but it would be interesting to see the actual puzzle you're facing; to see if anyone has any alternative approaches for you.

Dynamically building WHERE clauses in SQL statements

I have a question regarding SQL. I have the following SQL statement:
SELECT id, First, Last, E_Mail, Notes
FROM mytable
WHERE SOMETHING_SHOULD_BE_HERE IS NOT NULL;
I know that the SOMETHING_SHOULD_BE_HERE should be a column(attribute) in my table. Is their a way I can put a variable that can refer to the column I'm trying to access? In my case their are 30 columns. Can I have a string for SOMETHING_SHOULD_BE_HERE that can be assigned in my program to the column in which I want to search?
Thanks
No. Variables in SQL can refer to data, but not to object names (columns, functions or other database objects).
If you are building the SQL query, you'll need to use string operations to build your query.
The column can't be variable, but the value of the column can. The parser needs to know what to bind to.
If you elaborate on what you're trying to solve and which platform you're using it would allow for more complete answers.
You can have different SQLs queries in your code and use each one according to the case.
Another way is generate dynamically the query according the fields you want.
Without dynamic SQL, this is probably your best bet:
SELECT
id, first, last, email, notes
FROM
My_Table
WHERE
CASE #column_name_variable
WHEN 'column_1' THEN column_1
WHEN 'column_2' THEN column_2
...
ELSE 'not null'
END IS NOT NULL
There might be some issues with data type conversions, so you might need to explicitly cast all of the columns to one data type (VARCHAR is probably the best bet). Also, there's a good chance that performance will be horrendous on this query. I'd test it thoroughly before even thinking about implementing something like this.
I mentioned this in my comment, but for completeness I'll put it here too... you can probably also accomplish this with dynamic SQL, but how you do that will depend on your database server (MS SQL Server, Oracle, mySQL, etc.) and there are usually some caveats to using dynamic SQL.
In JDBC program, yes,the select statement can be composed like string operation.
for(String colName: colList)
{
String sql="Select id, First, Last, E_Mail, Notes From mytable where "+colName+" IS NOT NULL";
//execute the sql statement
}
It depends on how you are going to find out the value of SOMETHING_SHOULD_BE_HERE.
If you are in an Oracle PLS/SQL environment you could build up the WHERE clause using dynamic SQL and then use EXECUTE IMMEDIATE to execute it.
If you have a small set number of possibilities you could use CASE to workaround your problem possibly.
Your question is unclear.
However I am quite sure that what you have in mind is the so-called dynamic SQL (and related). "Dynamic SQL" allows you to dynamically build and submit queries at runtime. However such functionalities may not exist for your RDBMS.
There are several ways to do this.
When your query would return one and only one row
then you have to consider the EXECUTE IMMEDIATE statements (along with sp_executesql in tSQL : http://msdn.microsoft.com/en-us/library/ms188001.aspx ; or the USING clause in PL/SQL : http://docs.oracle.com/cd/B14117_01/appdev.101/b10807/13_elems017.htm to specify a list of input/output bind arguments) and/or PREPARED statements (http://rpbouman.blogspot.fr/2005/11/mysql-5-prepared-statement-syntax-and.html).
When your query can return more than one row
then you have to consider techniques such as the EXECUTE IMMEDIATE statement with the BULK COLLECT INTO clause or the OPEN-FOR, FETCH, and CLOSE statements (explicit cursors in PL/SQL :
http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/dynamic.htm)
Please note that except in some particular cases, most conventional techniques like IF-THEN-ELSE and CASE statements should be preferred (along with a good algorithm). Furthermore they work with almost all RDBMS.

Can you explain this SQL injection?

The website i worked was recently attempted to be hacked by the following SQL injection script
boys' and 3=8 union
select 1,
concat(0x232425,ifnull(`table_name`,0x30),char(9),ifnull(`table_rows`,0x30), char(9),0x252423),
3,4,5,6,7,8,9
from `information_schema`.`tables`
where table_schema=0x62646B3032 limit 44,1 -- And '8'='8
This injection returned the mysql table name. This was reported by the error reporting system on that website and we managed to fix that part however I am not able to understand what does the above injection mean?
Anyone can explain this?
Penuel
They're using a select from the Information Schema views in mysql server :
http://dev.mysql.com/doc/refman/5.0/en/information-schema.html
They use some clever hacks to rout out simple sql injection prevention techniques.
According to this the MySQL concat()
Returns the string that results from
concatenating the arguments. May have
one or more arguments. If all
arguments are nonbinary strings, the
result is a nonbinary string. If the
arguments include any binary strings,
the result is a binary string. A
numeric argument is converted to its
equivalent binary string form
So 0x232425 is converted to #$% which is simply added to the begining and end of the table_name field. Maybe just to make it easier for them to pull out the Table names later using Regex.
Later on the char(9) is equivalent to a tab as you can see here and is just there to format the output nicer.
The 3,4,5,6,7,8,9 is just there so that the columns match the boys table that they are performing the Union on.
This injection returned the mysql table name.
Do you mean that your website displayed the table name when you gave it this input, or that the query returns that when run from the mysql client? If it showed on your website, then the attacker has the ability to inject much more harmful queries. Check your data.