I have my classes from other projects which have strings for SQL queries.
See my example
public class OtherClass
{
myQuery = "SELECT * FROM v_My_View WHERE code = '#code'";
// I am targeting a view, not a stored procedure
}
My question is, if I use this in my commandText and just replace the #code with a value, is this valid argument against SQL injection?
If it is vulnerable with SQL injection - what are the other options for it?
I tried to use the
CMD.Parameters.AddWithValue("#code", _obj.code)
but it ruined my query.
I am using parameters when accessing my stored procedure, but not when accessing my views.
This is my main:
public class Main
{
public DataTable myMethod()
{
try
{
DataTable myTable = new DataTable("MyDataTable");
using (SqlCommand CMD = new SqlCommand())
{
CMD.Connection = RBOSUtil.DBConnection();
CMD.CommandType = CommandType.Text;
// this is the part I used the string from other class
CMD.CommandText = OtherClas.myQuery.Replace("#code", _obj.code);
using (SqlDataAdapter DA = new SqlDataAdapter(CMD))
{
DA.Fill(myTable);
}
}
}
catch
{
throw;
}
finally
{
//close connection
}
return myTable;
}
}
use this
public class Main
{
public DataTable myMethod()
{
DataTable myTable = new DataTable("MyDataTable");
try
{
using (SqlCommand CMD = new SqlCommand())
{
CMD.Connection = RBOSUtil.DBConnection();
CMD.CommandType = CommandType.Text;
//this is the part I used the string from other class
CMD.CommandText = OtherClas.myQuery;
CMD.Parameters.Add("#code", SqlDbType.NVarChar).value = _obj.code;
using (SqlDataAdapter DA = new SqlDataAdapter(CMD))
{
DA.Fill(myTable);
}
}
}
catch
{
throw;
}
finally
{
//close connection
}
return myTable;
}
}
declare datatable before try
You don't need quotes around the parameter name in the SQL statement:
myQuery = "SELECT * FROM v_My_View WHERE code = #code";. Otherwise what you're doing looks fine to me. It should work.
EDIT: I got confused between the original question and Ravi's answer. Somehow I missed the separator between the question and the first answer. Anyway, to answer the original question, yes, using String.Replace to replace #code with a value is subject to SQL injection vulnerabilities.
You should use SQL parameters, like the code in Ravi's answer, but you'll also need to modify the query to remove the quotes around the parameter name.
Related
I have a function which will get the records from the database.
public List<Issue> Load_Issues()
{
SqlDataReader Sdr;
List<Issue> ObjList = new List<Issue>();
cmd.CommandText = "Get_All_Issue";
try
{
cmd.Connection = con;
cmd.CommandType = CommandType.StoredProcedure;
con.Open();
Sdr = cmd.ExecuteReader();
while (Sdr.Read())
{
// here I pull out records from database..
}
}
catch (Exception ex)
{
throw ex;
}
finally
{
con.Close();
}
return ObjList;
}
The function I am using to bind the Gridview is as follows
public void Bind_Issues()
{
gdIssues.DataSource = Bl.Load_Issues()();
gdIssues.DataBind();
}
My stored procedure doesn't take any arguments. While the page loads for the first time it is working fine and binding the records to the gridview.
We have option to edit the records also, so what happening is after updating records I need to again bind the records to gridview. So I am again using my Load_Issues function to do it. But this time it is throwing error
Get_All_Issues has no parameters and arguments were supplied
You're most probably re-using the cmd instance in multiple places and you don't clear the parameters associated with it, thus creating the exception you're seeing.
Easiest fix would be to not re-use cmd, but if for whatever reason it's better for you, just make sure you use Clear on parameters before you execute it.
cmd.Parameters.Clear();
Try not using global connections, commands etc: open and close them within the method
public List<Issue> Load_Issues() {
//TODO: Put actual connection string here
using (SqlConnection con = new SqlConnection("Connection String here")) {
con.Open();
// Put IDisposable into using
using (SqlCommand cmd = new SqlCommand()) {
cmd.Connection = con;
cmd.CommandText = "Get_All_Issue";
cmd.CommandType = CommandType.StoredProcedure;
List<Issue> ObjList = new List<Issue>();
// Put IDisposable into using
using (var Sdr = cmd.ExecuteReader()) {
while (Sdr.Read()) {
//TODO: Pull out records from database into ObjList
}
}
return ObjList;
}
}
}
Try these
exec 'stored_procedure_name'
go
or
alter proc stored_procedure_name
as
begin
--Block of Statements
end
go
or
create proc stored_procedure_name
as
begin
--Block of Statements
end
go
Where go keyword will solved your problem.
So I want to create a line graph with data from a MySQL table and I've managed to draw one using the code below.
However, I want to pass a variable 'moduleID' to the MySQL query and I have done so, however, I'm not sure if this is the most appropriate way to do so. Should I pass a parameter instead and if so, how do I do that?
protected void chart(int moduleID)
{
string connStr = ConfigurationManager.ConnectionStrings["myConnectionString"].ConnectionString;
MySqlConnection conn = new MySqlConnection(connStr);
string comm = "SELECT * FROM scores WHERE module_id=" + moduleID.ToString();
MySqlDataAdapter dataAdapter = new MySqlDataAdapter(comm, conn);
DataSet ds = new DataSet();
Chart1.ChartAreas["ChartArea1"].AxisX.MajorGrid.Enabled = false;
Chart1.ChartAreas["ChartArea1"].AxisY.MajorGrid.Enabled = false;
Chart1.ChartAreas["ChartArea1"].AxisX.Minimum = 1;
Chart1.ChartAreas["ChartArea1"].AxisX.LabelStyle.Enabled = false;
Chart1.ChartAreas["ChartArea1"].AxisX.Title = "time";
Chart1.ChartAreas["ChartArea1"].AxisY.Minimum = 0;
Chart1.ChartAreas["ChartArea1"].AxisY.Maximum = 100;
Chart1.ChartAreas["ChartArea1"].AxisY.Title = "%";
Chart1.ChartAreas["ChartArea1"].AxisY.TextOrientation = TextOrientation.Horizontal;
try
{
conn.Open();
dataAdapter.Fill(ds);
Chart1.DataSource = ds;
Chart1.Series["Series1"].YValueMembers = "score";
Chart1.DataBind();
}
catch
{
lblError.Text = "Database connection error. Unable to obtain data at the moment.";
}
finally
{
conn.Close();
}
}
You are right. Concatenating strings to form a query is prone to SQL injection. Use parameters like:
string comm = "SELECT * FROM scores WHERE module_id=#module_id";
MySqlCommand mySqlCommand = new MySqlCommand(comm,conn);
mySqlCommand.Parameters.Add(new MySqlParameter("#module_id", module_id));
MySqlDataAdapter dataAdapter = new MySqlDataAdapter(mySqlCommand);
You should also enclose your connection and command object with using statement. This will ensure proper disposal of resource.
Also an empty catch is very rarely useful. You should catch specific exception first and then the base exception Exception in an object. Use that object to log the exception information or show in your error message. This will provide you help in debugging your application.
Step1: Create stored Procedure
CREATE PROCEDURE SelectScore
(#moduleID NCHAR(50))AS
SELECT * FROM scores WHERE module_id=#moduleID
Step2: Call the stored Procedure from Code
string connStr = ConfigurationManager.ConnectionStrings["myConnectionString"].ConnectionString;
using (SqlConnection conn = new SqlConnection(connStr )) {
conn.Open();
// 1. create a command object identifying the stored procedure
SqlCommand cmd = new SqlCommand("SelectScore", conn);
// 2. set the command object so it knows to execute a stored procedure
cmd.CommandType = CommandType.StoredProcedure;
// 3. add parameter to command, which will be passed to the stored procedure
cmd.Parameters.Add(new SqlParameter("#moduleID ", moduleID ));
// execute the command
using (SqlDataReader rdr = cmd.ExecuteReader()) {
// iterate through results, printing each to console
while (rdr.Read())
{
..
}
}
}
What is the easiest and most SQL-like way to insert textbox values into a SQL Server table? I found several ways, and all of them are too complicated for this simple thing I want to do.
If LINQ is too foreign for you, you can still do things the old-fashioned way:
string statement = "INSERT INTO mytable(mycolumn) VALUES (#text)";
SqlCommand command = new SqlCommand(statement);
command.Parameters.AddWithValue("#text", myTextBox.Text);
try{
SqlConnection connection = new SqlConnection(myConnectionString);
connection.Open();
command.Connection = connection;
command.ExecuteNonQuery();
} catch {
//do exception handling stuff
}
Edit: Here's another version that uses using to ensure that messes are cleaned up:
string statement = "INSERT INTO mytable(mycolumn) VALUES (#text)";
using(SqlCommand command = new SqlCommand(statement))
using(SqlConnection connection = new SqlConnection(myConnectionString)) {
try{
command.Parameters.AddWithValue("#text", myTextBox.Text);
connection.Open();
command.Connection = connection;
command.ExecuteNonQuery();
} catch {
//do exception handling stuff
}
}
If you want to do something quickly, use LINQ to SQL. It will take care of your Data Access Layer & Business objects.
Just go to LINQ to SQL Classes on Visual Studio & map your SQL server and add any tables you want to it.
Then you can use the objects it creates in your code behind to update values from textboxes.
http://weblogs.asp.net/scottgu/archive/2007/05/19/using-linq-to-sql-part-1.aspx
public string ConnectionString
{
get
{
//Reading connection string from web.config
return ConfigurationManager.ConnectionStrings["ConnectionName"].ConnectionString;
}
}
public bool InsertEmployee()
{
bool isSaved = false;
int numberOfRowsAffected = 0;
string query = #"INSERT INTO Employee(EmployeeName, EmailAddress)
VALUES (#EmployeeName, #EmailAddress);
SELECT ##IDENTITY AS RowEffected";
SqlCommand cmd = new SqlCommand();
cmd.CommandText = query;
cmd.CommandType = System.Data.CommandType.Text;
cmd.Parameters.Add(new SqlParameter("#EmployeeName", txtEmployeeName.Text));
cmd.Parameters.Add(new SqlParameter("#EmailAddress", txtEmailAddress.Text));
try
{
using (SqlConnection cn = new SqlConnection(ConnectionString))
{
cmd.Connection = cn;
cn.Open();
object result = cmd.ExecuteScalar();
isSaved = Convert.ToInt32(result) > 0 ? true : false;
}
}
catch (Exception ex)
{
isSaved = false;
}
return isSaved;
}
But, in multiple layer or multi-tier application you do need to create DTO(Data Transfer Object) to pass the data from layer to layer(or tier to tier)
Here's a simple way to do it. It looks complex because of the number of rows: Inserting Data in SQL Database
I'd like to call a stored function in C#. I need articles and some examples for this.
It's almost identical to how you would call a SQL Server Stored Procedure:
using(MySqlConnection conn = new MySqlConnection(connString))
{
MySqlCommand command = new MySqlCommand("spSomeProcedure;", conn);
command.CommandType = System.Data.CommandType.StoredProcedure;
// Add your parameters here if you need them
command.Parameters.Add(new MySqlParameter("someParam", someParamValue));
conn.Open();
int result = (int)command.ExecuteScalar();
}
http://forums.asp.net/p/988462/1278686.aspx
MySqlCommand cmd = new MySqlCommand("DeleteMessage", new MySqlConnection(GetConnectionString()));
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new MySqlParameter("param1", MessageItem.Entry_ID));
cmd.Connection.Open();
int i = cmd.ExecuteNonQuery();
cmd.Connection.Close();
Stored routines
Stored functions and stored procedures are called in different ways.
Stored function is used as regular function in SQL statement.
For example
SELECT id, title, my_function(price) FROM table
Stored procedures are called using CALL statement.
CALL my_procedure(1,2,'title');
I don't know C#, so probably you can use MySqlCommand class to call stored procedures, but you can't use it to call stored functions.
I actually couldn't get the other methods suggested to return a value. I ended up creating a string to call the function and then executed that string with .ExecuteScalar:
MySqlTransaction mySqlTransaction = testDataMySqlConnection.BeginTransaction();
mySqlCommand = new MySqlCommand
{
Connection = testDataMySqlConnection,
CommandText = "SELECT sf_UnitsAttempted('" + ... + ");",
CommandType = CommandType.Text
};
var f = (float)mySqlCommand.ExecuteScalar();
mySqlCommand.Dispose();
return f;
I know the question is about returning from a stored function, and Justin's answer here covers that. I wanted to add that if you wanted to return a DataTable from a stored procedure instead, you can do it using a DataAdapter:
// using MySql.Data.MySqlClient; // remember to include this
/* Helper method that takes in a Dictionary list of parameters,
and returns a DataTable.
The connection string is fetched from a resources file. */
public static DataTable ExecuteProc(string procedureName, Dictionary<string,object> parameterList)
{
DataTable outputDataTable;
using (MySqlConnection MySqlConnection = new MySqlConnection(Resources.SQL_CONNECTION_STRING))
{
using (MySqlCommand sqlCommand = new MySqlCommand(procedureName, MySqlConnection))
{
sqlCommand.CommandType = CommandType.StoredProcedure;
if (parameterList != null)
{
foreach(string key in parameterList.Keys)
{
string parameterName = key;
object parameterValue = parameterList[key];
sqlCommand.Parameters.Add(new MySqlParameter(parameterName, parameterValue));
}
}
MySqlDataAdapter sqlDataAdapter = new MySqlDataAdapter(sqlCommand);
DataSet outputDataSet = new DataSet();
sqlDataAdapter.Fill(outputDataSet, "resultset");
outputDataTable = outputDataSet.Tables["resultset"];
}
}
return outputDataTable;
}
This is a really, really stupid question but I am so accustomed to using linq / other methods for connecting and querying a database that I never stopped to learn how to do it from the ground up.
Question: How do I establish a manual connection to a database and pass it a string param in C#? (yes, I know.. pure ignorance).
Thanks
using (SqlConnection conn = new SqlConnection(databaseConnectionString))
{
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText = "StoredProcedureName";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#ID", fileID);
conn.Open();
using (SqlDataReader rdr =
cmd.ExecuteReader(CommandBehavior.CloseConnection))
{
if (rdr.Read())
{
// process row from resultset;
}
}
}
}
One uses the SqlCommand class to execute commands (either stored procedures or sql) on SQL Server using ado.net. Tutorials abound.
Here's an example from http://www.csharp-station.com/Tutorials/AdoDotNet/Lesson07.aspx
public void RunStoredProcParams()
{
SqlConnection conn = null;
SqlDataReader rdr = null;
// typically obtained from user
// input, but we take a short cut
string custId = "FURIB";
Console.WriteLine("\nCustomer Order History:\n");
try
{
// create and open a connection object
conn = new
SqlConnection("Server=(local);DataBase=Northwind;Integrated Security=SSPI");
conn.Open();
// 1. create a command object identifying
// the stored procedure
SqlCommand cmd = new SqlCommand(
"CustOrderHist", conn);
// 2. set the command object so it knows
// to execute a stored procedure
cmd.CommandType = CommandType.StoredProcedure;
// 3. add parameter to command, which
// will be passed to the stored procedure
cmd.Parameters.Add(
new SqlParameter("#CustomerID", custId));
// execute the command
rdr = cmd.ExecuteReader();
// iterate through results, printing each to console
while (rdr.Read())
{
Console.WriteLine(
"Product: {0,-35} Total: {1,2}",
rdr["ProductName"],
rdr["Total"]);
}
}
finally
{
if (conn != null)
{
conn.Close();
}
if (rdr != null)
{
rdr.Close();
}
}
}
3 things no one else has shown you yet:
"Stacking" using statements
Setting an explicit parameter type rather than letting .Net try to pick one for you
"var" keyword
.
string sql = "MyProcedureName";
using (var cn = new SqlConnection(databaseConnectionString))
using (var cmd = new SqlCommand(sql, cn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#ParameterName", SqlDbType.VarChar, 50)
.Value = "MyParameterValue";
conn.Open();
using (SqlDataReader rdr =
cmd.ExecuteReader(CommandBehavior.CloseConnection))
{
if (rdr.Read())
{
// process row from resultset;
}
}
}