I am working in C# for the first time in awhile, I have a line of code like this.
SQL = string.Format("PageName = '{0}'", bp.CommandArgument);
I need to know how to secure the object "bp.CommandArgument" from any SQL Injection. Thank you.
Why don't you use sql parameters?
string commandTxt = "SELECT ... FROM ... WHERE PageName=#PageName";
var command = new SqlCommand(commandTxt, connection);
command.Parameters.Add("#PageName", bp.CommandArgument);
I assume that connection is the SqlConnection object you have declared.
Related
Exception:
Local variable/parameter ':your-param-name' can only be used within a database procedure.
In MSSQL, the param character is #. In INGRES Database, really is : ? I cannot find official documentation for that...
SELECT * FROM MyIngresTable WHERE MyColumn = :poorParam
C# with Spring.NET AdoTemplate:
IDbParametersBuilder builder = CreateDbParametersBuilder();
builder.Create().Name("poorParam").Type(DbType.Int32).Value(1);
Any help?
Solved!
Just use INTERROGATION without named param, and pass values in order of usage.
string query = "SELECT * FROM MyIngresTable WHERE MyColumn >= ? and OtherColumn = ?";
IDbParametersBuilder builder = CreateDbParametersBuilder();
builder.Create().Type(DbType.Int32).Value(10);
builder.Create().Type(DbType.String).Size(4).Value("test");
IList<YourModelType> data = AdoTemplate.QueryWithRowMapper(
CommandType.Text,
query,
new YourRowMapper<YourModelType>(),
builder.GetParameters()
);
Another tip about Spring.NET AdoTemplate:
using Spring.Data.Common;
using Spring.Data.Generic;
protected virtual IDbParametersBuilder CreateDbParametersBuilder()
{
return new DbParametersBuilder(AdoTemplate.DbProvider);
}
Thanks also, Panagiotis Kanavos.
The following query in C# doesn't work, but I can't see the problem:
string Getquery = "select * from user_tbl where emp_id=#emp_id and birthdate=#birthdate";
cmdR.Parameters.AddWithValue("#emp_id", userValidate.emp_id);
cmdR.Parameters.AddWithValue("#birthdate", userValidate.birthdate);
OdbcCommand cmdR = new OdbcCommand(Getquery, conn);
OdbcDataReader Reader = cmdR.ExecuteReader();
Reader.HasRows returns no result but when I query it to my database I got data.
I'll assume your code is actually not quite as presented, given that it wouldn't currently compile - you're using cmdR before you declare it.
First, you're trying to use named parameters, and according to the documentation of OdbcCommand.Parameters, that isn't supported:
When CommandType is set to Text, the .NET Framework Data Provider for ODBC does not support passing named parameters to an SQL statement or to a stored procedure called by an OdbcCommand. In either of these cases, use the question mark (?) placeholder.
Additionally, I would personally avoid using AddWithValue anyway - I would use something like:
string sql = "select * from user_tbl where emp_id = ? and birthdate = ?";
using (var connection = new OdbcConnection(...))
{
connection.Open();
using (var command = new OdbcCommand(sql, connection))
{
command.Parameters.Add("#emp_id", OdbcType.Int).Value = userValidate.EmployeeId;
command.Parameters.Add("#birthdate", OdbcType.Date).Value = userValidate.BirthDate;
using (var reader = command.ExecuteReader())
{
// Use the reader here
}
}
}
This example uses names following .NET naming conventions, and demonstrates properly disposing of resources... as well as fixing the parameter issue.
I do think it's slightly unfortunate that you have to provide a name for the parameter when adding it to the command even though you can't use it in the query, but such is life.
Use like this:
string Getquery = "select * from user_tbl where emp_id=? and birthdate=?";
cmdR.Parameters.AddWithValue("#emp_id", userValidate.emp_id);
cmdR.Parameters.AddWithValue("#birthdate", userValidate.birthdate);
OdbcCommand cmdR = new OdbcCommand(Getquery, conn);
OdbcDataReader Reader = cmdR.ExecuteReader();
while(Reader.Read())
{
//Do something;
}
I know this thread is old, but I wanted to share my solution for anyone else coming up on this.
I was having issues with the typical method that Jon posted. I have used it before, but for some reason with this new string I had it was not wanting to actually place the parameter correctly and was causing the reader to not work.
I ended up doing something like this instead, since in the end we are just replacing parts of a string.
string sql = "select * from user_tbl where emp_id = "+ var1 +" and birthdate = "+
var2""
OdbcCommand command = new OdbcCommand(sql);
This was easier for me to get to work. Be warned though, I am not sure if it has any specific drawbacks when compare to using the command parameter method.
I'm trying to understand why in C# if you have a sql string why you would have to put tick (') marks in the following where clause in order for this to work. Could someone please explain the reasoning behind this?
where ProgramServer='" + machineName.ToString() + "' and Active=1;
You can avoid those tick (') marks and use Parameters, They will also save you from SQL Injection.
The reason you see those ticks are because SQL expects string type values to be enclosed in single ticks.
What you're seeing is a dynamically built SQL query in the code. When querying based on a string value, the string must be wrapped in single quotes. The final SQL string would look something like:
select * from someTable where ProgramServer = 'YourMachineName' and Active = 1;
Unfortunately, that is far from the best way to do things. You should be using parameterized queries instead:
var query = "select * from someTable where ProgramServer = #machineName and Active = 1;";
using(var conn = new SqlConnection(connString))
{
var command = new SqlCommand(query, conn);
command.Parameters.Add("machineName", machineName.ToString());
// Execute and get the results
}
I followed this answer,
How can I supply a List<int> to a SQL parameter?
Please see these questions of mine for understanding scenario,
How can I update Crate IDs of List of Fruits in single SQL query in c#
how can i update SQL table logic
What I am trying and not working
private void relate_fruit_crate(List<string> selectedFruitIDs, int selectedCrateID)
{
string updateStatement = "UPDATE relate_fruit_crate set CrateID = #selectedCrateID where FruitID = #selectedFruitIDs";
using (SqlConnection connection = new SqlConnection(ConnectionString()))
using (SqlCommand cmd = new SqlCommand(updateStatement, connection))
{
connection.Open();
cmd.Parameters.Add(new SqlParameter("#selectedCrateID", selectedCrateID.ToString()));
cmd.Parameters.Add(new SqlParameter("#selectedFruitIDs", String.Join(",",selectedFruitIDs.ToArray())));
cmd.ExecuteNonQuery();
}
}
My code runs without any error,
You need to use the IN keyword in your scenario. The problem is that the SqlCommand.Parameters pattern does not build the query itself, but calls a stored procedure on the database:
exec sp_executesql N'UPDATE relate_fruit_crate set CrateID = #selectedCrateID where FruitID in(''#selectedFruitIDs'')', N'#selectedCrateID nvarchar(1),#selectedFruitIDs nvarchar(5)', #selectedCrateID = N'1', #selectedFruitIDs = N'1,2'
This will not work as the array is escaped.
The workaround would be to either use a normal StringBuilder to create the query. (Warning! SQL Injection) or to call the query for each ID separately.
Maybe there's a way to do this with the SqlCommand.Parameters, but I could not find one.
OLD POST::
string updateStatement = "UPDATE relate_fruit_crate set CrateID IN ('#selectedCrateID') where FruitID = '#selectedFruitIDs'";
[....]
cmd.Parameters.Add(new SqlParameter("#selectedFruitIDs", String.Join("','",selectedFruitIDs.ToArray())));
and equals (=) query will only match a single value.
Multi-value parameter queries are a bit of a pain in TSQL. There are options like table-valued parameters, or "split" UDFs - otherwise... it is a bit tricky. You end up having to add multiple parameters (depending on the data), and change the query to suit. If I may suggest... a library like "dapper" may help you here - it is designed to make scenarios like this easy:
using Dapper; // at the top of your code file, to enable dapper
...
private void relate_fruit_crate(List<string> selectedFruitIDs, int selectedCrateID)
{
// note the slightly unusual "in" here (no paranethesis) - that is because
// dapper is going to do some voodoo...
using (SqlConnection connection = new SqlConnection(ConnectionString()))
{
connection.Open();
connection.Execute(
"UPDATE relate_fruit_crate set CrateID = #selectedCrateID where FruitID in #selectedFruitIDs",
new { selectedFruitIDs, selectedCrateID });
}
}
here "dapper" does all the work of figuring out how to express that in using multiple parameters, adding the correct number of parameters. It is also just much easier (in particular, look at how little work we did with commands and parameters; it handles readers nicely too).
Dapper is freely available from NuGet
I was hoping to find an easy way to get a parameter list of a stored procedures parameters. If the procedure has 3 paramaters, I want a list like this:
param1
param2
param3
It would be best to be able to do this in C# Code, but SQL would suffice as well. Ideas?
select * from information_schema.parameters
where specific_name='your_procedure_name'
Also refer this post to know more methods
https://exploresql.com/2016/10/14/different-methods-to-get-parameter-list-of-a-stored-procedure/
For SQL Server this should work.
private void ListParms()
{
SqlConnection conn = new SqlConnection("my sql connection string");
SqlCommand cmd = new SqlCommand("proc name", conn);
cmd.CommandType = CommandType.StoredProcedure;
conn.Open();
SqlCommandBuilder.DeriveParameters(cmd);
foreach (SqlParameter p in cmd.Parameters)
{
Console.WriteLine(p.ParameterName);
}
}
You can do this without ever touching SqlConnection, which I find is a bonus.
This uses the SqlServer.Management.Smo namespace, so you need a reference to Microsoft.SqlServer.ConnectionInfo, Microsoft.SqlServer.Management.Sdk, and Microsoft.SqlServer.Smo in your project.
Then use the following code:
Server srv = new Server("serverNameHere");
srv.ConnectionContext.AutoDisconnectMode = AutoDisconnectMode.NoAutoDisconnect;
srv.ConnectionContext.LoginSecure = false; //if using username/password
srv.ConnectionContext.Login = "username";
srv.ConnectionContext.Password = "password";
srv.ConnectionContext.Connect();
Database db = srv.Databases["databaseNameHere"];
foreach(StoredProcedure sp in db.StoredProcedures)
{
foreach(var param in sp.Parameters)
{
string paramName = param.Name;
var dataType = param.DataType;
object defaultValue = param.DefaultValue;
}
}
If you're familiar with Enterprise Library, there's a good method which allows to DiscoverParameters(), using the Data Access Application Block.
DbCommand command = new DbCommand();
command.CommandText = #"myStoredProc";
command.CommandType = CommandType.StoredProcedure;
Database database = new SqlDatabase(myConnectionString);
database.DiscoverParameters(command);
// ...
Some links that might help:
DiscoverParameters Method;
Microsoft.Practices.EnterpriseLibrary.Data Namespace.
The above links refers to EntLib 3.1. Depending on the .NET Framework version you're using, you might also consider downloading the correct EntLib version for you following this link.