I have an SQL request where I need to concatenate data into the request:
if (dataChoosen != "randomValue")
{
sCondition = " WHERE RandomField = '" + dataChoosen + "' ";
}
cd.CommandText = "SELECT xData FROM table " + sCondition + "GROUP BY xxx";
As I need to concatenate the condition, I don't think I can use a prepared request?
Also, I already tryparse the 'dataChoosed' value because it comes from a textbox and I need an integer. So is the the tryparse enough to prevent SQL injection?
I would just use parameters, there's no reason not to.
if (dataChoosed != "randomValue")
{
sCondition = " WHERE RandomField = #dataChoosed ";
}
cd.CommandText = "SELECT xData FROM table " + sCondition + "GROUP BY xxx";
cd.Parameters.Add("#dataChoosed", SqlDbType.VarChar).Value = dateChoosed;
No, you are not on the safe side. Even if dataChoosed is an innocent integer value, bad boys can hurt you with, say, negative value format:
// It's good old "-1", with a bit strange format
// (let use "delete from table commit;" as an injection)
string dataChoosed = "1'; delete from table commit; --1";
// A little hack: let "-" sign be...
CultureInfo hacked = new CultureInfo("en-US");
hacked.NumberFormat.NegativeSign = "1'; delete from table commit; --";
Thread.CurrentThread.CurrentCulture = hacked;
if (dataChoosed != "randomValue")
{
int v;
// since "1'; delete from table commit; --1" is of correct fotmat it will be parsed
if (int.TryParse(dataChoosed, out v))
sCondition = " WHERE RandomField = '" + dataChoosed + "' ";
}
cd.CommandText = "SELECT xData FROM table " + sCondition + "GROUP BY xxx";
And, woe! Where's my table? The command text will be
SELECT xData FROM table = '1'; delete from table commit; --1'GROUP BY xxx
which is efficently two queries:
SELECT xData FROM table = '1'; -- the innocent one
delete from table commit; -- an arbitrary query from the attacker
(I've removed commented out --1'GROUP BY xxx fragment)
Please, use parameters, do not tempt us. Please, notice, that you don't want to change code: all you have to do is to change the Regional Settings in your Windows.
Does [BLANK] protect against sql injection?
Unless [BLANK] is 'parameters' the answer is always no.
Related
I'm going to execute SQL query directly on database.
I've define connection to my database using:
System.Data.Entity.DbContext rawDbContext = new DbContext(connectionString);
I don't want to insert parameters directly to query string to avoid SQL Injection so I want to set parametrized values for my SQL query this way:
string sqlCommandString =
"IF EXISTS(select* from #MappingTableName where " + Environment.NewLine +
"BranchID= #PrimaryKeyID and " + Environment.NewLine +
"BranchNo = #BranchNo and " + Environment.NewLine +
"TableName = #TableName and " + Environment.NewLine +
"BranchSchema = #SchemaNameInBranch and " + Environment.NewLine +
"TableID = #TableID) " + Environment.NewLine +
" select 1" + Environment.NewLine +
"ELSE " + Environment.NewLine +
"select 0 " + Environment.NewLine;
SqlParameter parameterMappingTableName = new SqlParameter("#MappingTableName", vipMappingTableName);
SqlParameter parameterSchemaNameInBranch = new SqlParameter("#SchemaNameInBranch", schemaName);
SqlParameter parameterPrimaryKeyInBranch = new SqlParameter("#PrimaryKeyID", primaryNodeId);
SqlParameter parameterBranchNo = new SqlParameter("#BranchNo", branchNo);
SqlParameter parameterTableId = new SqlParameter("#TableID", tableId);
SqlParameter parameterTableName = new SqlParameter("#TableName", tableName);
DbRawSqlQuery<int> result = rawDbContext.Database.SqlQuery<int>(sqlCommandString,
new[] {
parameterMappingTableName,
parameterSchemaNameInBranch,
parameterPrimaryKeyInBranch,
parameterBranchNo,
parameterTableId,
parameterTableName
});
int finalResult = result.Single();
Running this query leads to excpetion "Must declare the table variable \"#MappingTableName\"."
How can I fix this?
Check this from Microsoft forums
Database objects (tables, stored procedures or any other objects)
cannot be passed as parameters. Only actual values for columns or
variables can be parameters. You need to build your SQL statement
dynamically in this case
Which basically means that you have to provide and/or build the table name, under the danger that this can be compromised.
How to mitigate the risk. Declare a set of probable table name and do an exact match.
Then build your query with text concatenation. This is something that can't be done with parameters cause you can't expect the possible values, but can be done with tables because they are only so many. Be carefull to use Equals instead of Contains in your list of names.
I am fairly new to C#, and i am trying to make a teacher management program.
This is the function that i am using to execute the query.
string commentString = "sC" + (y + 1) + "Y" + (i + 1) + "";
executeQuery("UPDATE student SET " +
commentString + " = '" + s.getStudentCourses(i,y,s)+
"' WHERE sNumber = '" + s.getStudNumber(s) + "'");
My Query String:
query "UPDATE student SET 'sComments1-1' = 'wa5235' WHERE sNumber = 68721919" string
The exception i get:
[MySql.Data.MySqlClient.MySqlException] {"You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''sComments1-1' = 'wa5235' WHERE sNumber = 68721919' at line 1"} MySql.Data.MySqlClient.MySqlException
Here is the SQL data structure:
CREATE TABLE `NewTable` (
`sNumber` int(9) NOT NULL ,
`sFirstName` varchar(32) NOT NULL ,
`sLastName` varchar(32) NOT NULL ,
`sDOB` varchar(9) NOT NULL ,
`sGrade` int(1) NOT NULL ,
`sEmail` varchar(32) NULL ,
`sParentName` varchar(32) NOT NULL ,
`sParentPhone` varchar(11) NOT NULL ,
`sHomeAddress` varchar(32) NOT NULL ,
`sComments1-1` varchar(255) NOT NULL ,
Using MySQL 5.5
I do not know why, but this is giving me sql errors. Please help me, my assignment is due in 2 days and i really need this finished.
A duplicate of your problem (minus signs in column names) is asked and answered here:
MySQL INSERT - Do field names require backtick/accent delimination?
You need to use 'back-ticks' instead on single quotes when using the column name with a minus sign in your query. Like this:
UPDATE student SET `sComments1-1` = 'wa5235' WHERE sNumber = 68721919
There doesn't appear to be any way to get sComments1-1 from "sC" + (y + 1) + "Y" + (i + 1) + "" so I'm not sure why you think your query string is of the correct form.
In any case, your column names need to be surrounded by backticks rather than single quotes:
UPDATE student SET `sComments1-1` = ...
Assuming that sComments1-1 is a typo or earlier version, and should actually be one of multiple columns of the form sCaYb, where a and b are distinct integers, the code would look something like this:
// Get column name of form sC*Y* where *'s are distinct integers.
string commentColumn = "sC" + (y + 1) + "Y" + (i + 1);
// Execute query with correct quote types.
executeQuery("UPDATE student SET `" + commentColumn + "` = '" +
s.getStudentCourses(i,y,s) +
"' WHERE sNumber = " + s.getStudNumber(s));
I've added the backticks around the column name and removed them from the sNumber value (since it's an integer rather than a character column).
Have you tried removing the single quotes around your field names? unsure this will work but it's one thing i'd try.
if this doesn't help, let me know and i'll remove this answer
"UPDATE student SET 'sComments1-1' = 'wa5235' WHERE sN....
The Columnname 'sComments1-1' shouldnt be as a quoted string, just write the column name without the Quotes.
I usually use sql parameters with queries, but in this case I need to dynamically create more than just the parameters.
Could someone use injection on any of the variables? Aside from a stored procedure is there a simple way to protect against injection via code?
string whereClause = "WHERE " + filter.ToString() + " > " + nextStartPoint;
string orderBy = "ORDER BY " + filter.ToString() + " DESC";
ex
string sql = "SELECT TOP(" + numItemsToGet + ") * " +
"FROM Items " +
whereClause + " " +
orderBy;
Update
filter.ToString() is the actual column name
I'm surprised the following worked (partial ex)... I also thought you have to reference a column name with sql parameters.
cmd.Parameters.AddWithValue("Count", 10);
string sql = "SELECT TOP(#Count) * " +
Yes this is definitely subject to injection. If the user controls the filter parameter then it's very easy for them to inject bad SQL into your statement.
The simplest way to prevent an injection attack is to use SqlCommand to build up your command. It's designed to help prevent such attacks and will take the appropriate steps to protect your input
If you only have a finite set of possible filters, you can use an approach such as this, but this is a somewhat convoluted approach. I'd recommend using other tools, such as an OR mapper.
SET ROWCOUNT #numItemsToGet
select *
from Items
where
(
#ColumnANextStartPoint is null
or ColumnA > #ColumnANextStartPoint
) and (
#ColumnBNextStartPoint is null
or ColumnB > #ColumnBNextStartPoint
) and (
#ColumnCNextStartPoint is null
or ColumnC > #ColumnCNextStartPoint
)
order by
case #ColumnANextStartPoint when null then null else ColumnA end DESC,
case #ColumnBNextStartPoint when null then null else ColumnB end DESC,
case #ColumnCNextStartPoint when null then null else ColumnC end DESC
*My apologies, this code is untested.
The simple way to prevent SQL injection is to use parametrized queries like the following example:
SqlConnection someConnection = new SqlConnection(connection);
SqlCommand someCommand = new SqlCommand();
someCommand.Connection = someConnection;
someCommand.Parameters.Add(
"#username", SqlDbType.NChar).Value = name;
someCommand.Parameters.Add(
"#password", SqlDbType.NChar).Value = password;
someCommand.CommandText = "SELECT AccountNumber FROM Users " +
"WHERE Username=#username AND Password=#password";
someConnection.Open();
object accountNumber = someCommand.ExecuteScalar();
someConnection.Close();
There isn't enough information about the nature of filter and its string representations to rule it out. Possibly it's 100% safe because none of its possible values can cause injection, but possibly it's 100% unsafe because it's really easy to inject through it.
string queryString = "SELECT SUM(skupaj_kalorij)as Skupaj_Kalorij "
+ "FROM (obroki_save LEFT JOIN users ON obroki_save.ID_uporabnika=users.ID)"
+ "WHERE (users.ID= " + a.ToString() + ") AND (obroki_save.datum= #datum)";
using (OleDbCommand cmd = new OleDbCommand(queryString,database))
{
DateTime datum = DateTime.Today;
cmd.Parameters.AddWithValue("#datum", datum);
}
loadDataGrid2(queryString);
I tried now with parameters. But i don't really know how to do it correctly. I tried like this, but the parameter datum doesn't get any value(according to c#).
please try this :
database = new OleDbConnection(connectionString);
database.Open();
date = DateTime.Now.ToShortDateString();
string queryString = "SELECT SUM(skupaj_kalorij)as Skupaj_Kalorij "
+ "FROM (obroki_save LEFT JOIN users ON obroki_save.ID_uporabnika=users.ID)"
+ "WHERE users.ID= " + a.ToString()+" AND obroki_save.datum= '" +DateTime.Today.ToShortDateString() + "'";
loadDataGrid2(queryString);
when you use with Date, you must write like this
select * from table where date = '#date'
not like
select * from table where date = #date
While it's usually useful to post the error, I'd hazard a guess and say that you're getting a conversion error with your date.
You should really look at parameterising your queries...
You should read this: http://www.aspnet101.com/2007/03/parameterized-queries-in-asp-net/
And if you can't be bothered reading that, then try changing your 'a' variable to '1; DROP TABLE obroki; --' (but only after you back up your database).
Perhaps you need to write your SQL string in the SQL dialect of the database you're using. In Jet/ACE SQL (what's used by Access), the delimiter for date values is #, so you'd need this:
obroki_save.datum= #" +DateTime.Today.ToShortDateString() + "#"
Of course, some data interface libraries translate these things for you, so that may not be the problem here.
Ok, I have a list that consists of a bunch of values from a sql query, that part works fine. What I want to do is use the items in that list to tell another query what to look for. So, what it is saying is that, it should return all columns from CMMReports where PartNumber is like %listItem1..2...3%, Any advice?
List<string> ImportedParts = GetImportedPartNumbers();
string query = "SELECT * FROM CMMReports WHERE (RacfId IS NULL OR RacfId = '') AND (FilePath NOT LIKE '%js91162%') AND PartNumber LIKE %" + ImportedParts + "% ORDER BY CreatedOn DESC;";
Not that I condone this as you should be using parameterized queries. However, this should work:
StringBuilder partNumbers = new StringBuilder();
foreach (string queryValue in ImportedParts)
{
string q = "PartNumber LIKE '%" + queryValue + "%'";
if (string.IsNullOrEmpty(partNumbers.ToString())
{
partNumbers.Append(q);
}
else
{
partNumbers.Append(" OR " + q);
}
}
string query = string.Format("SELECT * FROM CMMReports WHERE (RacfId IS NULL OR RacfId = '') " +
"AND (FilePath NOT LIKE '%js91162%') AND ({0}) " +
"ORDER BY CreatedOn DESC;", partNumbers.ToString());
You might look up the IN clouse for SQL that way you get the answer for the parts that SQL Server can find in the database. Using WHERE x = y for all the items means that if one item can't be found the whole query returns nothing.
I would consider doing this in a stored procedure and passing in your list as an Xml parameter.
See the following article for more info on using Xml parameters in a stored proc:
Passing lists to SQL Server 2005 with XML Parameters - By Jon Galloway
Form there you can easily use your list data inside your stored proc using the Xml syntax and treat it almost as another table of data.
Untested, but you should get the idea:
List<string> ImportedParts = GetImportedPartNumbers();
SqlCommand cmd = myConnection.CreateCommand();
cmd.CommandText = "SELECT * FROM CMMReports WHERE (RacfId IS NULL OR RacfId = '') AND (FilePath NOT LIKE '%js91162%') AND (";
int i = 0;
foreach (string part in ImportedParts) {
cmd.AddParameterWithValue("#param" + i.ToString(), "%" + part + "%");
if (i != 0) cmd.CommandText += " OR"
cmd.CommandText += " PartNumber LIKE #param" + i.ToString();
i++;
}
cmd.CommandText += ") ORDER BY CreatedOn DESC;";
This solution uses a parameterized query instead of just appending strings in the SQL, which is considered a potential security risk.