What I want to achieve is, from this:
string[] QueryString = new string[]{
"Column1",
"Column2"
};
Create this:
SELECT Column1,Column2
FROM SomeTable
I know that I could do a concat but that's not a very clean way to doit.
I know that I could do a concat but that's not a very clean way to do it.
Seems pretty clean to me:
string sql = "SELECT " + string.Join(", ", QueryString) + " FROM SomeTable";
Although you're susceptible to SQL injection attacks:
string[] QueryString = new string[]{
" * FROM SomeTable; DROP TABLE SomeTable; --"
};
So ONLY do this if you have complete control of the column names that can be used (e.g. populated from the table metadata).
Declare #qtext varchar(max) = 'select '+column1+ ' , '+column2+ ' from sometable '
Exec(#qtext)
You could use String.Format
http://msdn.microsoft.com/en-us/library/system.string.format(v=vs.110).aspx
String query =
String.Format("SELECT {0}, {1} FROM SomeTable", QueryString[0], QueryString[1]);
Although, as always when constructing sql queries, be aware of sql injection attacks.
Related
I am trying to get indexes fragmentation info from database.
Here the dapper sql query:
var result = await _dbConnection.QueryAsync<IndexFragmentationModel>($#"
select
a.index_id as Id, name as Name, avg_fragmentation_in_percent as FragmentationPercent
from sys.dm_db_index_physical_stats (DB_ID(N'#dbName'), OBJECT_ID(N'#tableName'), null, null, null) as a
join sys.indexes as b on a.object_id = b.object_id and a.index_id = b.index_id;
", new
{
dbName = dbName,
tableName = tableName
});
return result.ToList();
Parameters are not passing the the places where they are expected.
Could anybody please suggest - maybe there is another way to pass them ?
You're using the literal strings "#dbName" and "#tableName", not the parameters' values.
Remove the N' and ' that surround them.
I was given a task to rewrite an old web API.
This API reads SQL queries from the database.
There's literally a view with "Queries" in the name which contains "SqlText" column.
SELECT SqlText FROM Queries WHERE QueryID = 123
The "SqlText" contains only simple SQL queries in the format SELECT [columns] FROM [table] by convention.
The query is altered depending on the URL parameters in the request. The result of this query is then shown as result.
string parsedColumns = ParseColumns(queryRow); //contains "Column1, Column2";
string parsedTable = ParseTable(queryRow); //contains "SomeTable"
string requestColumns = HttpContext.Request["columns"];
string sqlColumns = requestColumns ?? parsedColumns;
string col1Condition = HttpContext.Request["Column1"]
string col2Condition = HttpContext.Request["Column2"]
string sqlQuery = "SELECT " + sqlColumns
+ " FROM " + parsedTable
+ " WHERE Column1 = " + col1Condition
+ " AND Column2 = " + col2Condition;
This is obvious SQL injection issue so I started rewritting it.
Now there are three other problems.
I cannot change the structure of the database or the convention
The database is either Oracle or SQL Server
I don't know how to correctly work with the "columns" URL parameter to avoid SQL injection.
It's easy to convert the URL parameters in the WHERE clause to the SQL parameters for both SQL Server and Oracle.
SQL Server
var sqlCommand = new SqlCommand("SELECT * FROM SomeTable WHERE Condition1 = #con1 AND Condition2 = #con2");
Oracle
var oracleCommand = new OracleCommand("SELECT * FROM SomeTable WHERE Condition1 = :con1 AND Condition2 = :con2");
Column identifiers
The problem is with the HttpContext.Request["columns"]. I still need to somehow alter the SQL query string with URL parameters which I don't like at all.
To simplify the issue, let's consider a single column from URL request.
string column = HttpContext.Request["column"];
var cmd = new SqlCommand($"SELECT {column} FROM ...");
I know that in SQL Server the identifier can be surrounded by braces. So my line of thinking is that I'm safe if I strip all braces from the column.
string column = HttpContext.Request["column"];
column = column.Replace("[", "").Replace("]", "");
column = $"[{column}]";
var cmd = new SqlCommand($"SELECT {column} FROM ...");
Oracle uses quotation marks.
string column = HttpContext.Request["column"];
column = column.Replace("\"", "");
column = $"\"{column}\"";
var cmd = new OracleCommand($"SELECT {column} FROM ...");
The question
Is this sql-injection safe enough?
Or is this use case inherently sql-injection unsafe?
Since you are working with a basic program design that you cannot change what about just trying to add edits to the input to look for injection elements. For example if the input is a column name it will need to have a maximum length of 30 (before 12.x) characters and should not contain a semicolon or the strings " OR" or " AND" in them. While not a perfect solution this should be practical solution.
I am facing a problem , I have a query in SQL Server 2014, The query result should be based on a WHERE clause that takes a string from a C# CheckedListBox.
I have the string in this form (the following values are for example only) :-
cat,dog,bird,duck
And inside the database the records look like this:-
dog cat-dog cat-dog-duck bird-dog-duck etc...
I have tried this :-
DECLARE #animals nvarchar(max) = 'dog,bird,cat'
select x,y,z WHERE CHARINDEX(animals, replace(#animals,',',' ')) > 0
The result would show rows with only ONE SINGLE VALUE like dog cat bird But it wouldn't show rows with values like dog-cat dog-cat-bird etc! it just shows rows with one single word from #animals string.
How can I select all rows where column animals contains either a word or more from #animals string.
Thanks in advance...
You should create a temp table for store all searching value or you should create a temp table from the comma separated variable for the example visit Query for convert CSV values into temp table. Then use inner join for filter records from your table like below.
declare #temp table (animal varchar(50))
insert into #temp values ('cat')
insert into #temp values ('dog')
insert into #temp values ('bird')
select * from SomeTable a
inner join #temp t on a.Column like '%' + t.animal + '%'
Make stored procedure for that query and call it from C#.
And inside the database the records look like this:-
dog cat-dog cat-dog-duck bird-dog-duck etc...
There is the source of your problems. Before reading anything else I wrote in my answer, you should read Is storing a delimited list in a database column really that bad?, where you will see a lot of reasons why the answer to this question is Absolutely yes!.
Once you're done with that, the solution to the problem should be as obvious to you as it is to me - Fix the database structure - meaning remove that column storing delimited data and replace it with a table referenced by a many-to-many relationship to your existing table, that will hold the animals data for you.
The first part of the solution is using a table valued parameter instead of sending a delimited string to the database.
There are plenty of examples on how to do this on stackoverflow - like here and there.
Once you've done that, you can use a hack with like as a workaround, in case you can't change the database structure:
SELECT <ColumnsList>
FROM <TableName> As T
JOIN #TVP As TVP
ON '-' + T.Animals +'-' LIKE '%-' + TPV.Animal +'-%'
Note I've added the delimiter to both ends of both columns.
If you can change the structure you will have a query like this:
SELECT <ColumnsList>
FROM <TableName> As T
JOIN TableToAnimals AS TTA
ON T.Id = TTA.TableId
JOIN Aniamls AS A
ON TTA.AnimalId = A.Id
JOIN #TVP As TVP
ON A.Name = TVP.Animal
You should take a look at Table valued parameters, it will let you send in a table of values as a parameter from C# to SQL. You make a table with "animals" and then make a sub-select in your Stored Proc.
See example code from link below, shows how to pass the parameter:
// Assumes connection is an open SqlConnection object.
using (connection)
{
// Create a DataTable with the modified rows.
DataTable addedCategories = CategoriesDataTable.GetChanges(DataRowState.Added);
// Configure the SqlCommand and SqlParameter.
SqlCommand insertCommand = new SqlCommand("usp_InsertCategories", connection);
insertCommand.CommandType = CommandType.StoredProcedure;
SqlParameter tvpParam = insertCommand.Parameters.AddWithValue("#tvpNewCategories", addedCategories);
tvpParam.SqlDbType = SqlDbType.Structured;
// Execute the command.
insertCommand.ExecuteNonQuery();
}
https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/sql/table-valued-parameters
For anyone who has the same problem. I have found the solution for this on SQL Server. Use the Full Text Search and your problem is easily solved. It's awesome.
Check the following link :-
https://learn.microsoft.com/en-us/sql/relational-databases/search/get-started-with-full-text-search?view=sql-server-2017
use like this:
var query = string.Empty;
var index=0;
foreach(var animal in animals) {
if (query.Length>0) {
query +=" and ";
}
var paramName = "#animalName" + index++;
query +="(animals like " + paramName + " or animals like '%' + " + paramName + " or animals like " + paramName + " + '%' or animals like '%' + " + paramName + " + '%')";
SqlParameter thisParam = new SqlParameter(paramName, animal);
command.Parameters.Add(thisParam);
}
command.CommandText = "select * from tableName WHERE " + query;
My project has different SQL Server DataTable. I will bind the data from user request table. so got table name as
Example:
table = "MyTable"
How to write the SQL query for select the particular table.
con.open();
SqlAdaptor da = new SqlAdaptor ("select * from '" + table.replace(""", "\"")" + '")
cmd.ExecuteNonQuery();
My replace is not working so I hope to any one resolve my issue.
Just escape " character?1
table.Replace("\"", string.Empty);
Also you don't need single quotes for your table name. By the way if you get this table as an input, I will strongly suggest do some strong validation before you put it in your query or use a whitelist.
You didn't show us rest of your code but use using statement to dispose your connection and adapter objects.
1: Since it is an escape sequence character
You can also try
SqlAdaptor da = new SqlAdaptor ("Select * from " + table.Replace('"', ' ').Trim());
string table = "MyTable";
table.Replace('\"', ' '); //Or
table.Replace('\"',string.Empty);
I've got the following query that returns 2 records (in DataSet's query builder)
SELECT EmpID, Name, id
FROM Users
WHERE (CAST(id AS Varchar(20)) IN ('5688','5689'))
Now if I do the same query passing the parameter instead from code behind: String param = "'5688','5689'"; it returns null.
WHERE (CAST(id AS Varchar(20)) IN (#param))
I tried taking off the very first and last ', but that did not make a diffrence.
!!!id is a unique PK!!!
Anyone's got a clue?
The solution I found is quite simple, this works like a charm and there's no need for sps or other functions;
SQL:
SELECT whatever
FROM whatever
WHERE (PATINDEX('%''' + CAST(id AS Varchar(20)) + '''%', #param) > 0)
C#:
String param = "'''1234'',''4567'''";
dataTable1 = tableAdapter1.getYourValues(param);
A variable is not allowed in the IN clause.
You are expecting the values as a comma delimited string you could use the split function (user defined and non-standard) to join them with the original tables:
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=326300&SiteID=1
For more information you can visit this
('5688','5689') is an array of values.
Defining String param = "'5688','5689'"; and using it as (#param) makes ('5688','5689') a string. Which wont work.
Bibhas is correct. For me this worked:
string param="'1234','4567'"; we can't use param as SQL Parameter(#param).
command = new SqlCommand("SELECT * FROM table WHERE number IN (" + param + ")", connection);
command.ExcecuteReader();