I want to write sql command to text file with parameter values.
Following is my code for replacing parameter with appropriate values.
string commandText = commandInfo.CommandText;
if (commandInfo.Parameters.Count > 0)
{
foreach (SqlParameter parameter in commandInfo.Parameters)
{
commandText=commandText.Replace(parameter.ParameterName,parameter.Value==(object)DBNull.Value?(object)DBNull.Value:("'"+parameter.Value.ToString()+"'"));
}
}
the catch is although all other parameter values are replaced correctly.those having null values are taken up as blank i.e 'parameter1',,'param2'
between the two is the null valued parameter in final string.
What can be the alternative?
Frankly, replacing the parameters with values is (IMO) the wrong thing to do; what we do in mini-profiler is to spoof declare statements at the top of the output, so that you can copy and paste it into SSMS, without needing to worry about what is a parameter and what was hard-coded in the original TSQL. For example, glancing at the mini-profiler output for this page, I see
DECLARE #id int = 18121022,
#type tinyint = 10;
(and then lots of tsql that is very specific to us)
You can glance at the mini-profiler code to see how we output this, but basically it just involves walking over the parameters, writing a simple declare. If you are using something like ASP.NET, mini-profiler also avoids the need to write a file (instead making it available live on the site, to your developers).
Related
I often have to construct long and difficult queries "in code". I know, that I can pass any parameters using SqlDataAdapter.SelectCommand.Parameters.Add() method. But what should I do if i need in some cases make multiple concatenations like this:
var subquery = ConstructSubquery(param1, paramN);
query += subquery;
And so on. Code analyzer in VS offers me to use parameters instead of simple string concatenation, but something like
dataBaseSQL.SqlDataAdapter.SelectCommand.Parameters.Add("#subquery", SqlDbType.VarChar).Value = subquery;
//subquery = "WHERE param1 IN ('A', 'Z') AND param2 <> param3" (for example...)
does not work, of course! Queries are dynamic, subqueries are generated by special functions.
What is the best decision?
Parameters are for values, not for statements (or pieces of statements).
A and Z are values that can be put in a parameter (let's say #value1 and #value2) (and we will ignore the complexity of doing the IN operator using a variable number of parameters... there is an hard limit on the number of parameters in SQL Server, 2100). So for example WHERE param1 IN (#value1, #value2) is perfectly ok...
You can't put the whole WHERE param1 IN (#value1, #value2) in a parameter.
You shouldn't/mustn't let the user write SQL statements or piece of SQL statements (so no SELECT or WHERE written by the user), it is very highly insecure, and I don't think it can really be secured.
Even letting the user fill the name of columns to be selected can be insecure. Always ask yourself: what happens if the user writes, as the column name, for example?
-- DROP TABLE SomeTable --
And even letting the user select the column names from a "closed list" could be insecure, because 9 times out of 10 you won't check if the user manipulated the javascript of the page to write whatever he wants in the combobox/listbox (it is quite easy... press F12 on Chrome and the whole javascript of the page is in your hands).
So I have sproc1 which does some things and returns some rows. The important thing is it does some things. I also have sproc2 which does some things, calls sproc1 (which does it's own things) and returns it's own rows. The problem is when I call sproc2 I get 2 result sets. First comes from sproc1 and second comes from sproc2.
Is it possible to easily suppress the sproc1 when calling it in sproc2?
I have two ways to do this as far as I can tell:
use a temporary table to catch the output of the exec sproc.
in C# navigate to the last result set and use that while ignoring the first one(s).
None of these methods is easily reusable as the:
first requires me to CREATE a temporary table that matches the output of the stored procedure
second needs me to iterate through the result sets to get to the last one not knowing which is the last one unless I try to move to the next and fail via .NextResult().
The easy way would be if SQL Server allowed me to exec a stored procedure within another stored procedure, but suppress the output of the inner executed it. Or if SqlCommand allowed an ExecuteReader(CommandBehavior.LastResult) and would navigate to the last result by itself.
Can any of the two be achieved in an easy and reusable manner?
The real solution would be to refactor inner stored procedures into write and read components. Or add a #param to inner stored procedures that prevents the final results from being selected. But I'm trying to be lazy here!
So (for now, unless I find a better answer or something gets improved) I ended up adding this argument with a default value so I don't have to think about it at all in the C# side:
,#_Suppress bit = 0 -- prevent output via select
and right before the select I add:
if #_Suppress is null or #_Suppress = 0
select -- output results
This method also requires you to refactor insert ... output code and output into a temporary table and eventually only select if not suppressed.
This is the easiest method to handle things but there should be internal functionality for these cases like:
begin suppress
exec some_sproc;
end suppress;
or some special syntax like sexec (as in suppressed exec) or a general use NULL table that can accept any insert columns format and just discard it.
I'll probably add this argument from now on to all my sprocs that produce results and refactor the old ones impacted by this issue.
Currently I simply don't allow apostrophe's at all (along with other character's as you can see) with this, reiterated for each field:
foreach(char c in Comments)
{
if(c=='\'' || c=='$' || c=='\"' || c=='&' || c=='%' || c=='#' || c=='-' || c=='<' || c=='>')
{
errorMessage = "You have entered at least one invalid character in the \"Comments\" field. Invalid characters are: [\'], [\"], [&], [$], [#], [-], [<], [>], and [%]";
}
}
I've been coding this for a while, and I am getting better, but the real problem is that, while I am sure there is a way to effectively "strip-out" or otherwise validate the user input, I am not sure which approach is best and probably wouldn't until a security crisis was imminent.
If I have to, I will settle on simply never allowing single quotes into the form at all (as it is now), however this may aggravate anyone named say... Bill O'Reilly for the name field, etc., etc.
There are probably other (well I don't know what to call them, 'plug-ins?' 'outside programs?') that would do the job for me, but that is virtually useless since not only do I have no idea how to integrate that, I would have no idea how to tailor it specifically to my web interface/database.
Is there any code that could help me detect a sql injection apostrophe (by the characters surrounding it maybe?) from a normal apostrophe? Keep in mind some of my fields can hold up to 500 characters (textareas) and one up to 1,000.
Thanks for any ideas or help!
No amount of input encoding/cleanup will be as safe as parametrized queries.
See SqlCommand.Parameters for details on parametrized queries.
string commandText = "SELECT * FROM Sales WHERE CustomerID = #ID;";
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlCommand command = new SqlCommand(commandText, connection);
command.Parameters.Add("#ID", SqlDbType.Int);
command.Parameters["#ID"].Value = customerID;
var reader = command.ExecuteReader();
//.....
}
SQL Injections is not a problem with the input containing specific characters, it's a problem with how you handle the input.
By disallowing certain characters you can stop the obvious ways to cause SQL injections, but it's virtually impossible to use that to stop all possible ways.
If encoded correctly, there are no character that causes problems. The best way of doing that for database calls is to use parameterised queries, so that the database driver takes care of encoding the correct characters according to the data type and the specific database.
Also, you need to encode the values correctly when you use them later on, like HTML encoding strings that are put in HTML code, URL encoding strings that are used in an URL (and both for strings that are put in an URL in the HTML code.)
You should use parameterised queries to prevent SQL Injection as other people have already said.
Alexei Levenkov provides a good example of using ADO.NET parameters, but more commonly, you will use the Database Helper when working with WebMatrix Razor pages (ASP.NET Web Pages Framework) where parameter handling is slightly different. The Database.Query method (Query(string commandText, params object[] parameters) takes a string representing the SQL to be executed, and an array of objects, representing the parameter values to be passed to the SQL. The Database helper expects parameter markers to start at #0, and increment by 1 each time e.g.
var sql = "SELECT * From MyTable WHERE TheDate > #0 AND ID > #1";
Then you pass actual values in the following manner:
var data = Database.Open("MyDb").Query(sql, Request["date"], Request["id"]);
Internally, the Database class takes care of matching values to placeholders and creating ADO.NET parameters for you.
I'm trying to figure out how best to organise an inline c# page that makes a number of DB connections and passes values to strings and need some advice.
So basically a CMS in use with my place of work only allows for inline code so I'm doing a course search page that hooks up to some stored procedures and passes the values to strings.
What would be the best way to handle three different stored procedure calls that output different bits of information to strings? In the old VB version I was passing info to strings then outputting them as one large string which probably isn't the best way to handle this.
The code currently goes in this rough format
Stored Procedure 1
Pass x values to string
string = "<p> + xString +</p>"
Stored Procedure 2
Pass y values to string
string = "<p> + yString +</p>"
Is there a smarter way for me to close off sections as each procedure section usually has a table involved or appends to one larger table and I'm just trying to see what people would suggest would be best practice.
Please note I'm really not much of a programmer and just dipping my toes so apologies if this is a school boy mistake.
There are a number of ways of concatenating strings:
You could use a StringBuilder. This type allows you to Append and Insert text and then output all the text with the ToString() method.
StringBuilders are usually used when adding text to a string from within a loop. (I've read that using a StringBuilder is encouraged once you have over 10 concatenations)
Since you only have to append text to your string 3 times you can just use:
String.Concat or yourString += string.Format("<p>{0}</p>", stringToBeAdded);
In your case the texts may not be relevant to eachother, in which case there are other options available:
// Using an array (fixed size)
string[3] yourStrings;
yourStrings[0] = "first string";
yourStrings[2] = "last string";
// Using a list (dynamic sized)
var yourStrings = new List<string>();
yourStrings.Add(storedProcResult.ToString());
I would suggest that you try and make the question clearer, however if I understand correctly I think it would probably be best to create a stored procedure which runs the other stored procedures and stores the results in temp tables e.g.
INSERT INTO #MyTable1 EXEC procedure1 #param
INSERT INTO #MyTable2 EXEC procedure2 #param
INSERT INTO #MyTable3 EXEC procedure3 #param
Then in the same stored procedure run a simple select statement that concatenates the strings as desired and returns them to your inline code e.g.
SELECT CONCAT( MyTable1.emp_name, MyTable2.emp_middlename, MyTable3.emp_lastname ) AS Result
I've been looking through the documentation on string formatting in .Net and haven't found this bit yet, and was hoping someone could point me in the right direction. I've come across a working piece of code that takes SqlParameters and puts them in a string like this:
SqlParameter[] arrParams = new SqlParameter[]
{
new SqlParameter("#ClientID", clid),
new SqlParameter("#CustomerID", cuid),
new SqlParameter("#AdminUser", false)
};
string sqlText = string.Format("Insert into [Table1] (RID, CustomerID, AdminUser) values (#ClientID,#CustomerID,#AdminUser)");
..and when running that string down the line in a SqlCommand the proper values are put into the right spots. I'm used to using curly braces for string formatting arguments and not the #symbol and so was wondering where to learn more about this?
This code does not actually need String.Format.
String.Format is for times when you would normally do "string" + variable + "more string". This would be written as String.Format("string{0}morestring", variable); In this case, it is just one string, so that is why there is no need...nothing is being concatenated together.
Here is a good explanation of String.Format
What is happening here is that the #VariableName is being filled with your SqlParameters to avoid SQL Injection. In a nutshell, when you create a SqlParameter, the .NET library looks for either a SQL parameter that matches the name, which could be a stored procedure, function, etc, or any item in a SQL text that begins with # and matches the name.
And here is a good explanation of how SqlParameters work
I think there is some confusion here. The # symbol is used to identify the named SQL parameters within the INSERT INTO statement and not for String.Format.
This is not similar to String.Format what is actually happening is you are running the SQL Command, the command looks for variables called #ClientID,#CustomerID and #AdminUser, which are passed to SQL Server as parameters. You will have something like cmd.Parameters = arrparams a bit further down.
The actual String.Format part around the SQL text is redundant you are right, it will been to use the curly brace route like you suggested.
Hope this helps.