I know that this probably has been answered before, but I have rewritten this single line 10 times it still won't work. I have assured myself that this is written properly, yet it won't work.
This is my last resort. Here's a screenshot:
For security reasons, and for the exact reason you are asking, you should not be setting raw T-SQL in theCommandText property of your SqlCommand.
In your case, your string likely has ' characters in it that are breaking your query making the syntax invalid.
Instead, you CommandText should be initialized with Parameters, for example:
findItForMe.CommandText = "SELECT Name, LicenseType, till FROM myTable WHERE SomeColumn = #SomeParameter"
Then in your findItForMe command add the Parameters.
findItForMe.Parameters.AddWithValue("#SomeParameter", Somevalue)
Building your findItForMe SqlCommand this way will fix your errors and prevent malicious actors from perform SQL injection hacks against your application.
A full example:
string name = "Jacob's Ladder";
string commandText = "SELECT Name, LicenseType, till FROM myTable WHERE Name = #Name";
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlCommand findItForMe = new SqlCommand(commandText, connection);
// Use AddWithValue to assign name
// The parameterized query will escape your strings and keep you safe from hackers.
command.Parameters.AddWithValue("#name", name);
try
{
connection.Open();
SqlDataReader dr = command.ExecuteReader();
while (dr.Read())
{
// do something here
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
Related
I have the following code which seems pretty standard on face value, however in query is another SQL statement hence why the 'AS QUERY' is at the end of the SQL string. I wanted to know if there was a sophisticated approach to parameterising the following SQL command instead of concatenating the entire query together.
The only solution I could think of would be to instead of having a query as a string, have it as an SQLCommand type object and initiate 2 commands. 1 to could and the other to display the preview of the data.
public static CommandStatus<int> GetQueryRecordCount(SqlConnection connection, String query)
{
String sql = "SELECT COUNT(1) FROM (" + query + ") AS QUERY";
SqlCommand cmd = new SqlCommand();
cmd.CommandType = CommandType.Text;
cmd.CommandText = sql;
cmd.Connection = connection;
cmd.CommandTimeout = GetTimeout();
try
{
SqlDataReader dataReader = cmd.ExecuteReader();
dataReader.Read();
String count = dataReader[0].ToString();
dataReader.Close();
return new CommandStatus<int>(Int32.Parse(count));
}
catch (Exception e)
{
return new CommandStatus<int>("Failed to GetQueryRecordCount[" + sql + "]:" + e.Message, e);
}
}
String SQL will end up being something like this
"SELECT COUNT(1) FROM (SELECT TOP 20 [RecordID],[Name],[SonsName],[DadsName],[MothersName],[DaughtersName] FROM [dbo].[sample] ) AS QUERY"
This function is literally SQL injection by design.
Whitelisting the SQL queries this function will accept is the only way to make it safe.
That is, the caller won't be able to inject any SQL query, they'll only be able to pick from a fixed list of pre-vetted queries. The list could even be defined as an array of static strings in the function you show.
But then they don't need to pass the whole query as a string, they only need to pass an ordinal integer to identify which query in the whitelist to run.
C#, Razor
my code is:
#using (SqlConnection Praktikum2 = new SqlConnection("Data Source=Mark\\SQLEXPRESS;Initial Catalog=Connection;Integrated Security=True"))
{
using(connection)
{
SqlCommand command = new SqlCommand("SELECT KategoryID FROM Kategory WHERE Name = " + Request.Params["kategory"]);
connection.Open();
SqlDataReader reader = command.ExecuteReader(); //ERROR!!!
while (reader.Read())
{
string ID = reader["KategorieID"].ToString() ;
Console.WriteLine("ID = {0}", ID);
}
reader.Close();
};
}
i get an error that there's a wrong syntax near "=".
how can i solve this?
The problem is caused by the missing quotes around the value passed for your search. You could add a set of single quote before and after the value obtained by the Request but that would be a bigger error and the source of a problem called Sql Injection.
The only way to handle this is to use a parameter query
SqlCommand command = new SqlCommand(#"SELECT KategoryID FROM Kategory
WHERE Name = #name", connection);
command.Parameters.Add("#name", SqlDbType.NVarChar).Value = Request.Params["kategory"];
Also, as noted in another answer, your code seems to not have associated the connection to the command, I think that it is just a typo here because the error message in that case would be 'need an open connection'
You forgot to assign the connection to the command. So when you call ExecuteReader(), it does not know on which connection it should be executed.
You can assign the connection like this:
SqlCommand command = new SqlCommand(
"SELECT KategoryID FROM Kategory WHERE Name = " + Request.Params["kategory"],
connection); // provide connection as second parameter!
or use connection.CreateCommand() to create your command.
Second, you forgot the quotation marks around your string:
"SELECT KategoryID FROM Kategory WHERE Name = '" + Request.Params["kategory"] + "'"
but inserting user data directly into your query opens your code to SQL Injection. Please use parameterized queries instead.
If your kategory column is not of integer data type then you need to surround your value with (') i.e single quote characters
Then your query will be like
SqlCommand command = new SqlCommand("SELECT KategoryID FROM Kategory WHERE Name ='" + Request.Params["kategory"] + "'");
The exception is caused by how you are creating your sql statement. The fix should not be correcting the syntax but using parameters instead. This will prevent sql injection attacks.
Also
You really should not be writting sql in your views, do it in your controller method instead and return the result in the Model to be used in your view. Better yet, abstract it to a different layer and call that layer from your controller. This has to do with SoS (Separation of Concerns), your code will very difficult to maintain if you just write everything into your views.
Wrap your connections, commands, and readers in using blocks.
Modified Code
#{
using(SqlConnection Praktikum2 = new SqlConnection("Data Source=Mark\\SQLEXPRESS;Initial Catalog=Connection;Integrated Security=True"))
using(SqlCommand command = new SqlCommand("SELECT KategoryID FROM Kategory WHERE Name = #name", Praktikum2))
{
command.Parameters.Add(new SqlParameter("#name", SqlDbType.VarChar){ Value = Request.Params["kategory"]});
connection.Open();
using(SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
string ID = reader["KategorieID"].ToString() ;
Console.WriteLine("ID = {0}", ID);
}
}
}
}
When I run the following code:
query = "select count(*) from table where name = '?name'";
MySqlConnection connection =
new MySqlConnection(ConfigurationManager.ConnectionStrings["mydb"].ToString());
connection.Open();
MySqlCommand command = new MySqlCommand(query,connection);
command.Parameters.Add("?name", name);
Int32 number = command.ExecuteScalar();
number is always zero, even when cast to an int.
I have tried converting it to int64, no dice. I have tried command.Prepare(). I have tried using Convert.ToInt32() and every other variation. I have tried just about everything under the sun including quoting verbatim what this suggests and I get no dice. Trying to cast the object as an integer, as a long, as an int32, none of this seems to work. These results are always 0 or cause a MySQL error.
EDIT: Stack overflow will not format that code properly in code tags, i apologize
The reason for that is because the parameter is enclose with single quote thus making it a string. Remove it and it will work,
query = "select count(*) from table where name = #name";
MySqlConnection connection = new MySqlConnection(ConfigurationManager.ConnectionStrings["mydb"].ToString());
connection.Open();
MySqlCommand command = new MySqlCommand(query,connection);
command.Parameters.Add("#name", name);
for better code,
use using for proper object disposal
using try-catch block for proper handling of exceptions
code snippet,
query = "select count(*) from table where name = #name";
string connString =ConfigurationManager.ConnectionStrings["mydb"].ToString();
using(MySqlConnection connection = new MySqlConnection(connString))
{
using(MySqlCommand command = new MySqlCommand(query, connection))
{
command.Parameters.Add("#name", name);
try
{
connection.Open();
// other codes
}
catch(MySqlException ex)
{
// do somthing with the exception
// don't hide it
}
}
}
I have text area on my page. In that area I have to add some HTML code and save it to database. And it works for simple html, but when I select some text from "wikipedia" for example and paste it and try to save when SQL Query need to be executed I got exception with following error:
Incorrect syntax near 's'.
The identifier that starts with '. Interestingly, old maps show the name as <em>Krakow</em>.</p>
<p>Kragujevac experienced a lot of historical turbulence, ' is too long. Maximum length is 128.
The identifier that starts with '>Paleolithic</a> era. Kragujevac was first mentioned in the medieval period as related to the public square built in a sett' is too long. Maximum length is 128.
The label 'http' has already been declared. Label names must be unique within a query batch or stored procedure.
The label 'http' has already been declared. Label names must be unique within a query batch or stored procedure.
Unclosed quotation mark after the character string '>Belgrade Pashaluk</a>.</p>'
I am using asp mvc and razor engine. I don't know maybe I need to encome html somehow. I have also added this for ArticleText property:
[AllowHtml]
public string ArticleText { get; set; }
This is code for saving to database:
string sql = #"insert into tbl_articles
(Text) values
("'" + article.ArticleText"'"+")";
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.ExecuteNonQuery();
Wow, NO, NO, NO. Your code is vulnerable to SQL injection and very bad stuff will happen if you don't use parametrized queries. So use parametrized queries.
using (var conn = new SqlConnection("some conn string"))
using (var cmd = conn.CreateCommand())
{
conn.Open();
cmd.CommandText = "insert into tbl_articles (Text) values (#Text)";
cmd.Parameters.AddWithValue("#Text", article.ArticleText);
cmd.ExecuteNonQuery();
}
Everytime you use the + operator to concatenate strings when building a SQL query you are doing something extremely dangerous and wrong.
Try to save this way:
string sqlQuery = "INSERT INTO tbl_articles (Text) VALUES (#text)";
SqlCommand cmd = new SqlCommand(sqlQuery, db.Connection);
cmd.Parameters.Add("#text", article.ArticleText);
cmd.ExecuteNonQuery();
Try:
string sql = #"insert into tbl_articles
(Text) values
(#articleText)";
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.Parameters.AddWithValue("#articleText",
Server.HtmlEncode(article.articleText));
cmd.ExecuteNonQuery();
This is a classic example of opening your system to a Sql injection attack.
You need to escape the ' character because if the Html contains the ' character, it will break the SQL Statement when it is executed.
EDIT: Use Darins solution to solve the problem.
this should be parameterized:
public void foo(string connectionString, string textToSave)
{
var cmdString = "insert into tbl_articles (text) values (#text)";
using (SqlConnection conn = new SqlConnection(connectionString))
{
using (SqlCommand comm = new SqlCommand(cmdString, conn))
{
comm.Parameters.Add("#text", SqlDbType.VarChar, -1).Value = textToSave;
comm.ExecuteNonQuery();
}
}
}
(this is the gereral idea, it's not completely functional as written.)
I am having a table which has three fields, namely LM_code,M_Name,Desc. LC_code is a autogenerated string Id, keeping this i am updating M_Name and Desc. I used normal update command, the value is passing in runtime but the fields are not getting updated. I hope using oledb parameters the fields can be updated.
Here is my code.
public void Modify()
{
String query = "Update Master_Accounts set (M_Name='" + M_Name + "',Desc='" + Desc + "') where LM_code='" + LM_code + "'";
DataManager.RunExecuteNonQuery(ConnectionString.Constr, query);
}
In DataManager Class i am executing the query string.
public static void RunExecuteNonQuery(string Constr, string query)
{
OleDbConnection myConnection = new OleDbConnection(Constr);
try
{
myConnection.Open();
OleDbCommand myCommand = new OleDbCommand(query, myConnection);
myCommand.ExecuteNonQuery();
}
catch (Exception ex)
{
string Message = ex.Message;
throw ex;
}
finally
{
if (myConnection.State == ConnectionState.Open)
myConnection.Close();
}
}
private void toolstModify_Click_1(object sender, EventArgs e)
{
txtamcode.Enabled = true;
jewellery.LM_code = txtamcode.Text;
jewellery.M_Name = txtaccname.Text;
jewellery.Desc = txtdesc.Text;
jewellery.Modify();
MessageBox.Show("Data Updated Succesfully");
}
This annoyed me, screwy little OleDB, so I'll post my solution here for posterity. It's an old post but seems like a good place.
OleDB doesn't recognize named parameters, but it apparently does recognize that you're trying to convey a named parameter, so you can use that to your advantage and make your SQL semantic and easier to understand. So long as they're passed in the same order, it'll accept a variable as a named parameter.
I used this to update a simple Access database in a network folder.
using (OleDbConnection conn = new OleDbConnection(connString))
{
conn.Open();
OleDbCommand cmd = conn.CreateCommand();
for (int i = 0; i < Customers.Count; i++)
{
cmd.Parameters.Add(new OleDbParameter("#var1", Customer[i].Name))
cmd.Parameters.Add(new OleDbParameter("#var2", Customer[i].PhoneNum))
cmd.Parameters.Add(new OleDbParameter("#var3", Customer[i].ID))
cmd.Parameters.Add(new OleDbParameter("#var4", Customer[i].Name))
cmd.Parameters.Add(new OleDbParameter("#var5", Customer[i].PhoneNum))
cmd.CommandText = "UPDATE Customers SET Name=#var1, Phone=#var2" +
"WHERE ID=#var3 AND (Name<>#var4 OR Phone<>#var5)";
cmd.ExecuteNonQuery();
cmd.Parameters.Clear();
}
}
It may look like an excess of code, and yes you're technically repeating yourself, but this makes it worlds easier when you're playing connect-the-dots later on.....
You are close with the rest of your connection and such, but as you note, doing it with parameterized queries is safer from SQL-Injection...
// Some engines used named parameters, others may not... The "?"
// are "place-holders" for the ordinal position of parameters being added...
String MyQuery = "Update MyTable set SomeField = ?, AnotherField = ? "
+ " where YourKeyField = ?";
OleDbCommand MyUpdate = new OleDbCommand( MyQuery, YourConnection );
// Now, add the parameters in the same order as the "place-holders" are in above command
OleDbParameter NewParm = new OleDbParameter( "ParmForSomeField", NewValueForSomeField );
NewParm.DbType = DbType.Int32;
// (or other data type, such as DbType.String, DbType.DateTime, etc)
MyUpdate.Parameters.Add( NewParm );
// Now, on to the next set of parameters...
NewParm = new OleDbParameter( "ParmForAnotherField", NewValueForAnotherField );
NewParm.DbType = DbType.String;
MyUpdate.Parameters.Add( NewParm );
// finally the last one...
NewParm = new OleDbParameter( "ParmForYourKeyField", CurrentKeyValue );
NewParm.DbType = DbType.Int32;
MyUpdate.Parameters.Add( NewParm );
// Now, you can do you
MyUpdate.ExecuteNonQuery();
Just to add to RJB's answer, it's a little-known fact that OleDb actually DOES accept named parameters. You've just got to declare the parameters in SQL as well.
See: low-bandwidth.blogspot.com.au/2013/12/positional-msaccess-oledb-parameters.html
If you DON'T declare the parameters in SQL, OleDb uses purely positional parameter insertion, and it doesn't matter if the names of the parameters match the SQL, or if parameters are used twice in the SQL - it will just go through and blindly replace any found parameters in the SQL in order from start to end, with those passed.
However if you DO declare the parameters correctly, you get the benefit of named parameters and parameters allowed to be repeated multiple times within the SQL statement.