public ActionResult PostMessage(string message)
{
MessageController mc = new MessageController();
mc.postMessage(message);
}
What can I do here to prevent SQL injection in this string? This is the only input the user is given on the entire page. I am familiar with the some PHP techniques, but how would I protect myself in c#?
Thanks!
edit:
connection.Open();
SqlCommand command = new SqlCommand("[dbo].[tblMessages_Insert]", connection);
command.CommandType = CommandType.StoredProcedure;
// params
SqlParameter messageText = new SqlParameter("#messageText", SqlDbType.VarChar);
messageText.Value = message;
// add params
command.Parameters.Add(messageText);
rows = command.ExecuteNonQuery();
It seems to me that you're already protecting against injection; you're using parameters.
Related
Having a bit of an issue getting my insert to work properly. When I run the insert all within the same method, it works flawlessly... however when I try to send the Insert statement to my new Connection class (which I will have handle all database requests), I am getting the following error.
Note: I am using C# and Microsoft SQL Server.
System.Data.SqlClient.SqlException (0x80131904): Must declare the scalar variable "#CollectionGroupID".
I believe I am not sending the parameters over, however I am not sure of the best way to do this.
Here's my AddGame method:
public static void AddGame(int gameId)
{
string statement = "INSERT INTO Collection (CollectionGroupID, SharedID, UserID, GameID, Owned, Favorited, WishList, DeletedIndicator, AddUser, AddDate, ModUser, ModDate) VALUES (#CollectionGroupID, #SharedID, #UserID, #GameID, #Owned, #Favorited, #WishList, #DeletedIndicator, #AddUser, #AddDate, #ModUser, #ModDate)";
using (SqlCommand cmd = new SqlCommand())
{
cmd.Parameters.AddWithValue("#CollectionGroupID", "0");
cmd.Parameters.AddWithValue("#SharedID", "0");
cmd.Parameters.AddWithValue("#UserID", "0");
cmd.Parameters.AddWithValue("#GameID", gameId);
cmd.Parameters.AddWithValue("#Owned", "Y");
cmd.Parameters.AddWithValue("#Favorited", "N");
cmd.Parameters.AddWithValue("#WishList", "N");
cmd.Parameters.AddWithValue("#DeletedIndicator", "N");
cmd.Parameters.AddWithValue("#AddUser", "test/admin");
cmd.Parameters.AddWithValue("#AddDate", DateTime.Now);
cmd.Parameters.AddWithValue("#ModUser", "test/admin");
cmd.Parameters.AddWithValue("#ModDate", DateTime.Now);
Connection.Open();
Connection.Statement(statement);
Connection.Close();
}
}
And here is my Statement method in my Connection class
public static void Statement(string sql)
{
Console.WriteLine("Attempting to submit data to the database...");
try
{
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.ExecuteNonQuery();
}
catch (SqlException e)
{
Console.WriteLine(e);
}
}
I feel like perhaps I am overlooking a simple solution. Any help appreciated!
-Travis W.
Command parameter is defined in SqlCommand in your AddGame method
you are passing the raw Sql over to the Statement method and inside the method you are creating another SqlCommand without parameter defined. This is why the parameters are not being passed in.
you should just do
using (SqlConnection connection = new SqlConnection(connectionString))
{
//OR using (SqlConnection connection = Connection.Open())
//If you want to keep your Connection class to avoid having to pass in connection string.
using (SqlCommand cmd = new SqlCommand(statement, connection))
{
...
cmd.ExecuteNonQuery ()
}
}
inside your AddGame method
the code i'm using is below. Is this the proper way to use Session? also how do I call companyID and userID to clarify, if i did Session. is it Session.Contents or Session.Keys? this is my first time using session, I know I use httpcontact.current.user to access most of this but i'm not sure how to access each part of the data.
Thanks!
MySqlConnection cn = new MySqlConnection("Server=localhost;Database=users; User=root;Password=00;");
cn.Open();
string storedProcedureName = "VLID";
MySqlCommand cmd = new MySqlCommand(storedProcedureName, cn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#userName", this.Login1.UserName);
cmd.Parameters.Add("#passwordID", this.Login1.Password);
MySqlDataReader dr = cmd.ExecuteReader();
if (dr.HasRows)
{
dr.Read();
string userID = dr["userID"].ToString();
string companyID = dr["CompanyID"].ToString();
string sessionID = Session.SessionID.ToString();
Session.Add(companyID, "companyID");
Session.Add(userID, "userID");
e.Authenticated = true;
Response.Redirect("index.html");
// Event Authenticate is true
}
You are calling Session.Add method a little backwards:
Session.Add takes a key and a value, in that order; therefore, on your code you want:
Session.Add("companyID",companyID );
Session.Add("userID",userID );
But instead, you could do this, too:
Session["companyID"]=companyID;
Session["userID"]=userID;
Then, whenever you need to retrieve the userID value that you stored previously, you can do:
string userID= Session["userID"] as string;
As a side note, I wouldn't mix data access code on the UI code as you are doing.
The code that gets the data from the database should be moved to the data access layer (DAL).
And when you instantiate a database connection, always enclose it in an using statement so that is properly disposed when it comes out of scope:
using(MySqlConnection cn = new MySqlConnection("Server=localhost;Database=users; User=root;Password=00;"))
{
cn.Open();
//rest of the code
}
I tried to insert some data into my database (sql server/local file) but it doesn't work.
public bool SaveCookie(string cookie, string expires)
{
SimpleDBM db = new SimpleDBM();
db.Connect();
try
{
string query = string.Format("INSERT INTO Cookies(cookie_value, cookie_expires) VALUES('{0}', '{1}');", cookie, expires);
SqlCommand cmd = new SqlCommand();
cmd.CommandText = query;
//...
SqlDataReader data = db.Query(ref cmd);
return data.Read();
}
catch
{
return false;
}
finally
{
db.Close();
}
}
The SimpleDBM class:
public class SimpleDBM {
public static string dbpath = #"...";
public static string dbname = "db.mdf";
public static string dfullPath = Path.Combine(dbpath, dbname);
public static string connStr = string.Format(#"Data Source=.\SQLEXPRESS;AttachDbFilename={0};Integrated Security=True;Connect Timeout=30;User Instance=True", dfullPath);
private SqlConnection con;
public void Connect()
{
con = new SqlConnection();
con.ConnectionString = connStr;
con.Open();
}
public SqlDataReader Query(ref SqlCommand cmd)
{
cmd.Connection = con;
return cmd.ExecuteReader();
}
public void Close()
{
con.Close();
}
}
Can someone point out my mistake? For other queries it seems to work fine.
Thanks in advance.
The problem seems to be that you're trying to execute a query that doesn't return a result set using the ExecuteReader method of the SqlCommand class which will attempt to execute your query and create and return a DataReader for an eventual result set.
You should use ExecuteNonQuery for INSERT and UPDATE sql statements.
SIDE NOTE
Not that it's the reason you're getting the error but you should also consider using SqlParamters instead of composing the values into the INSERT statement. Using prepared SQL statements generally gives a performance enhancement and also helps prevent SQL injection attacks.
For an example of using prepared statements, see the MSDN page or the Prepare method.
You are using a ExecuteReader when you should be using ExecuteNonQuery.
Not related to your error you really should not be using String.Format with SqlCommand. What you should do is
string query = "INSERT INTO Cookies(cookie_value, cookie_expires) VALUES(#cookie, #expires);", cookie, expires);
SqlCommand cmd = new SqlCommand();
cmd.Parameters.AddWithValue("#cookie", cookie);
cmd.Parameters.AddWithValue("#expires", expires);
cmd.CommandText = query;
With your method ask your self if someone passed a cookie of ' ''); Drop table Cookies --? This is called a "Sql Injection Attack" and is one of the top 5 reasons websites get hacked.
EDIT
Just to help give another example of why using String.Format to pass values you did not generate is bad.
In an attempt to close my question on connections remaining open and exceeding the maximum pool, I'm trying tor rewrite the function that is used to connect to our database.
The function exists within a homegrown compiled library. using reflector I can see the code looks like this:
public SqlProvider([Optional, DefaultParameterValue("")] string StrConnection)
{
string str;
if (StrConnection == "")
{
str = ConfigurationSettings.AppSettings["ConStr"];
}
else
{
str = StrConnection;
}
SqlConnection connection = new SqlConnection(str);
connection.Open();
this.MyCommand = new SqlCommand();
SqlCommand myCommand = this.MyCommand;
myCommand.Connection = connection;
myCommand.CommandType = CommandType.Text;
myCommand = null;
this.MyDataAdapter = new SqlDataAdapter(this.MyCommand);
this.MyCommandBuilder = new SqlCommandBuilder(this.MyDataAdapter);
this.MyDataSet = new DataSet();
}
I'm planning on amending this to read
public SqlProvider([Optional, DefaultParameterValue("")] string StrConnection)
{
string str;
if (StrConnection == "")
{
str = ConfigurationSettings.AppSettings["ConStr"];
}
else
{
str = StrConnection;
}
using (SqlConnection connection = new SqlConnection(str))
{
connection.Open();
this.MyCommand = new SqlCommand();
SqlCommand myCommand = this.MyCommand;
myCommand.Connection = connection;
myCommand.CommandType = CommandType.Text;
myCommand = null;
this.MyDataAdapter = new SqlDataAdapter(this.MyCommand);
this.MyCommandBuilder = new SqlCommandBuilder(this.MyDataAdapter);
this.MyDataSet = new DataSet();
}
}
and then recompiling the dll.
Given that an instance of SQLProvider() is typically created at the top of a public class, and then that instance is used within class members (eg:
public class Banner
{
DSLibrary.DataProviders.SqlProvider db = new DSLibrary.DataProviders.SqlProvider(Defaults.ConnStr);
public Banner()
{
}
public DataTable GetBannerImages(string bannerLocation,int DeptId)
{
using (DSLibrary.DataProviders.SqlProvider db = new DSLibrary.DataProviders.SqlProvider(Defaults.ConnStr))
{
DataTable dt = new DataTable();
//Add Parameter #BannerLocation for Banner of Specific Location
//Call proc_getBannerImages Stored procedure for Banner Images
db.AddStoredProcParameter("#BannerLocation", SqlDbType.VarChar, ParameterDirection.Input, 100, bannerLocation);
db.AddStoredProcParameter("#DeptId", SqlDbType.Int, ParameterDirection.Input, 0, DeptId);
dt = db.ExecuteStoredProcedure("proc_getBannerImages");
return dt;
}
}
}
am I going about this the right way? It seems to me the connection will be disposed of before the data has actually been retrieved. Also, Visual Studio tells me that SQLProvider() must be implicitly convertible to System.IDisposable - how would I go about implementing this?
I tried wrapping all the members of class Banner in a using (DSLibrary.DataProviders.SqlProvider db = new DSLibrary.DataProviders.SqlProvider(Defaults.ConnStr)){} statement but intellisense then displays a "Invalid token 'using' in class, struct, or interface member declaration" error.
What is the best way to go about this?
UPDATE
I've tried disassembling adjusting and recompiling the DSLibrary, but as CHris_Lively says, I thinkit's doing nothing for me. Changing the instance in question to what I preceive to be a more standard format works so far:
public DataTable GetBannerImages(string bannerLocation,int DeptId)
{
using (SqlConnection conn = new SqlConnection(Defaults.ConnStr))
{
SqlCommand cmd = new SqlCommand("proc_getBannerImages", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("#BannerLocation", bannerLocation));
cmd.Parameters.Add(new SqlParameter("#DeptId", DeptId));
SqlDataAdapter da = new SqlDataAdapter();
da.SelectCommand = cmd;
DataTable dt = new DataTable();
da.Fill(dt);
return dt;
}
}
I'm about to look into the Enterprise library, seems like it might be the way forward.
It is not recommended to hold on to connections any longer than required (See also Chapter 14 of Improving .NET Application Performance and Scalability: Patterns and Practices from Microsoft Press).
In practice I'd change your class to instead not have the SqlConnection (or SqlDataAdapter or SqlCommandBuilder) as a member on the class (if you must, then you should implement the IDisposable pattern), but instead create new instances, wrapped in using statements on the class methods that need to use them.
I DO NOT think you are doing it correctly. As soon as you hit the end of the using block, the SqlConnection variable will become unusable . If you want to use it outside the constructor, dont put the using {} around the SqlConnection variable (The sqlcommand variable MyCommand is using it indirectly outside the constructor).
Instead, make you SqlProvider class implement IDisposable, and call Dispose on the MyCommand, MyDataAdapter, MyDataSet etc. variables there.
You probably should have something like this in your SqlProvider class :
public void Dispose()
{
if (MyCommand != null)
{
MyCommand.Dispose();
}
//... Similarly for MyDataAdapter,MyDataSet etc.
}
Your class needs to implement the IDisposable interface if you want to use it in a using block. See http://msdn.microsoft.com/en-us/library/system.idisposable.dispose%28v=VS.100%29.aspx for guidelines on dispose() and IDisposable.
You're close. However, a couple issues.
First, it looks like that whole DSLibrary isn't buying you anything at all.
When doing data access you typically want to structure it where acquiring the connection and executing the command are in the same function. You're methods should only return the result of the operation. This way you can cleanly use the IDisposable interface of the connection, command, and reader.
The following example uses Enterprise Library. Note that the Db doesn't have a using clause. It doesn't implement IDisposable. Instead, the command is responsible for letting go of the connection when it goes out of scope:
public static DataTable GetBannerImages(String bannerLocation, Int32 departmentId)
{
DataTable result = new DataTable();
result.Locale = CultureInfo.CurrentCulture;
Database db = DatabaseFactory.CreateDatabase("NamedConnectionStringFromConfig");
using (DbCommand dbCommand = db.GetStoredProcCommand("proc_getBannerImages"))
{
db.AddInParameter(dbCommand, "BannerLocation", DbType.String, bannerLocation);
db.AddInParameter(dbCommand, "DeptId", DbType.Int32, departmentId);
using (IDataReader reader = db.ExecuteReader(dbCommand))
{
SopDataAdapter dta = new SopDataAdapter(); // descended from DbDataAdapter
dta.FillFromReader(result, reader);
} // using dataReader
} // using dbCommand
return result;
} // method::GetBannerImages
You probably already have something that will convert a reader to a datatable, if not just look into subclassing the System.Data.Common.DbDataAdapter class
I've had tremendous success with the Enterprise Library. It's fast, efficient, and when going this route I've never had memory leaks or db connection issues.
There is no need to set variables to null - anyway they will be deleted by GC.
Also you need to call Dispose() or Close() for all classes that implements IDisposable. e.g. SqlConnection.
You can do that manually:
SqlConnection conn = null;
try
{
// use conn
}
finally
{
if (conn != null)
conn.Close();
}
or automatically using using block:
using (SqlConnection = new SqlConnection())
{
// use conn
}
(as you do)
Also you can decrease your code a bit using operator ?:
string str = String.IsNullOrEmpty(StrConnection) ? ConfigurationSettings.AppSettings["ConStr"] : StrConnection;
or ??:
string str = StrConnection ?? ConfigurationSettings.AppSettings["ConStr"];
the underlying database on a project has changed from sql 2005 to MySql 5.1
The code has loads of method similar to below. I'm presuming it is just a case of switching the 'con' variable SqlConnection to a MYSql specific connection. Has anyone had any experience with this? I have never touched a mySql db. Any help much appreciated.
private SqlConnection con;
public User LogonUser(string pUserName, string pPassword)
{
con = new SqlConnection();
con.ConnectionString = DatabaseConstants.DB_CONN_STRING;
using (con)
{
con.Open();
var command = new SqlCommand();
command.Connection = con;
command.CommandText = "SELECT id FROM Users WHERE userName = #userName AND password = #password";
command.CommandType = CommandType.Text;
var userName = new SqlParameter("#userName", pUserName);
var password = new SqlParameter("#password", pPassword);
command.Parameters.Add(userName);
command.Parameters.Add(password);
User user;
var dr = command.ExecuteReader();
if (dr != null)
if (dr.HasRows)
{
while (dr.Read())
{
user = new User();
user.id = dr.GetString(0);
return user;
}
}
else
{
throw new Exception("Can not find user, please check your username and password");
}
}
return null;
}
You got it partially correct, but you will need an instance of the MySQL Provider, not the SqlConnection. Also you will have to change any SQL that isn't compatible with MySQL.
Downloadable SQL Connectors are available for various frameworks and platforms - in this case assemblies to reference into your .NET project under the guise of ADO.NET are available from MySql. Can program against them using any .NET language.
Start in C# by referencing the MySql namespace:
using MySql.Data.MySqlClient;
and change over your ADO.NET class names from SqlConnection to MySqlConnection, etc. Google Code examples show cursory usage (similar to other ADO.NET providers), and of course the MySql docs are the best reference.
No, you have to also change this line
var command = new SqlCommand();
to
var command = new con.CreateCommand();
and of course you have to change any specific T-SQL and MSSQL features to MySQL. Date and time function, stored procedure, and parameter binding(? instead of #) are a few things that you need to closely check.