Here are some simple codes that search for the value in TargetColumn where SourceColumn = SourceValue.
Here are these codes:
string cmdText = "select * from " + TableName + " where " + SourceColumn + " = '" + SourceValue + "'";
SqlCommand dbCommand = new SqlCommand(cmdText, dbConnection);
SqlParameter sqlParam = new SqlParameter("#" + SourceColumn, SourceValue);
dbCommand.Parameters.Add(sqlParam);
SqlDataReader dbReader = dbCommand.ExecuteReader();
dbReader.Read();
string _targetValue = dbReader[TargetColumn].ToString();
dbReader.Close();
dbCommand.Dispose();
return _targetValue;
And my questions are:
I passed SourceColumn and SourceValue to SqlCommand using SqlParameter, will this make it SQL injection proof?
Do I need to use TargetColumn together with SqlParameter too for SQL safety purpose? (but it is for SqlDataReader)
If I use SqlParameter for SqlCommand, do I still need to compose a command text in a string and pass it to SqlCommand before SqlParameter is used?
Why do I need to add an "#" for SourceColumn? (I just followed the tutorial and added it) And why SourceValue doesn't need an "#"?
The above codes works well to return the expected value, but I'm so not sure about the above questions.
Thanks very much!
Related
I have a Window Application in ado.net with adding, modifying and deleting rows for a few tables. My problem is that after modifying a table with money type, the money value is much bigger after the operation.
String sql = "UPDATE kierowca SET imie='" + txtImie.Text + "',nazwisko='" + txtNazwisko.Text + "',data_zatrudnienia='" + txtData.Text + "',pensja='" + Convert.ToDecimal(txtPensja.Text) + "' WHERE imie='" + listBox2.SelectedItem.ToString() + "' AND nazwisko='" + listBox3.SelectedItem.ToString() + "';";
conn.Open();
cmd = new SqlCommand(sql, conn);
cmd.ExecuteNonQuery();
cmd.Clone();
conn.Close();
pensja in my table is type of money. What am I dong wrong?
I would give you an example of a parameterized query using your data
String sql = #"UPDATE kierowca SET imie=#imie,nazwisko=#nazwisko,
data_zatrudnienia=#data_zatrudnienia,pensja=#pensja
WHERE imie=#search1 AND nazwisko=#search2";
using(SqlConnection con = new SqlConnection(......))
using(SqlCommand cmd = new SqlCommand(sql, con))
{
cmd.Parameters.Add("#imie", SqlDbType.NVarChar).Value = txtImie.Text;
cmd.Parameters.Add("#nazwisko", SqlDbType.NVarChar).Value = txtNazwisko.Text;
cmd.Parameters.Add("#data_zatrudnienia", SqlDbType.NVarChar).Value = txtData.Text;
cmd.Parameters.Add("#pensja", SqlDbType.Decimal).Value = Convert.ToDecimal(txtPensja.Text);
cmd.Parameters.Add("#search1", SqlDbType.Decimal).Value = listBox2.SelectedItem.ToString();
cmd.Parameters.Add("#search2", SqlDbType.Decimal).Value = listBox3.SelectedItem.ToString();
con.Open();
int rowsChanged = cmd.ExecuteNonQuery();
MessageBox.Show("Updated " + rowsChanged + " rows");
}
Notice that I assume two things here.
The Convert.ToDecimal doesn't fails (better use decimal.TryParse to test if the input is indeed a decimal value).
The other fields involved in your query are all of type text (nvarchar on db)
Why this should work? Because with this code a parameter of type decimal and whose value is a decimal value is passed to the database engine. So the engine don't need to convert a string back to a decimal. This conversion could easily fails or give incorrect results if the a locale decimal point (comma) is not interpreted correctly by the database conversion code
Of course if your fields are of different type you should change the SqlDbType value in all the affected parameters
I know that non parameterized queries are frowned upon because of SQL injection. Well, I have a lot of queries in my application that are susceptible to SQL injection. I just can't seem to wrap my head around doing it with SqlDataReader. I am able to do it with ExecuteNonQuery just not SQLDataReader.
Can someone give me some pointers and or examples of the best way to do this, the query is executing and returning exactly what it should, I just want to make it as secure as possible....
Code:
string myQuery = "Select [shoeSize] AS 'Shoe Size', [shoeBrand] AS 'Shoe Brand' FROM [myTable] "
+ "WHERE [customerName] = '" + customer + "' AND " + "[customerPin] = '" + customerID + "'";
sqlCmd = new SqlCommand(myQuery, conn);
sqlCmd.Connection.Open();
SqlDataReader rdr2 = sqlCmd.ExecuteReader();
if (rdr2.HasRows)
{
rdr2.Read();
shoeSize= rdr2["Shoe Size"].ToString();
shoeBrand= rdr2["Shoe Brand"].ToString();
}
conn.close();
There you go
string myQuery = "Select [shoeSize] AS 'Shoe Size', [shoeBrand] AS 'Shoe Brand' FROM [myTable] "
+ "WHERE [customerName] = #customerName AND [customerPin] = #customerID"
sqlCmd = new SqlCommand(myQuery, conn);
sqlCmd.Connection.Open();
sqlCmd.Parameters.AddWithValue("#customerName", customerName);
sqlCmd.Parameters.AddWithValue("#customerID", customerID");
--rest stays the same as before
Whereas #customerName and #customerID are now your parameters. So even if the customer's name should be something like "Bigler, Fabian' DROP TABLE [myTable]" it will not work. It completely removes the possibility of "evil" input changing the meaning of your query.
Non-parameterized queries are not simply 'frowned upon'. It can be disastrous for you, your company and - of course - your customer.
Like this:
string myQuery = "Select [shoeSize] AS 'Shoe Size', [shoeBrand] AS 'Shoe Brand' FROM [myTable] "
+ "WHERE [customerName] = #customerName AND [customerPin] = #customerPin";
sqlCmd = new SqlCommand(myQuery, conn);
sqlCmd.Connection.Open();
sqlCmd.Parameters.Add("#customerName", SqlDbType.NVarChar, 50).Value = customer;
sqlCmd.Parameters.Add("#customerPin", SqlDbType.NVarChar, 20).Value = customerID;
SqlDataReader rdr2 = sqlCmd.ExecuteReader();
if (rdr2.HasRows)
{
rdr2.Read();
shoeSize = rdr2["Shoe Size"].ToString();
shoeBrand = rdr2["Shoe Brand"].ToString();
}
conn.close();
I have some trouble with the SqlDataReader:
public string GetVareNavn(string streg)
{
string navn = "";
SqlConnection myCon = DBcon.getInstance().conn();
string query =
"SELECT Navn FROM Vare WHERE Stregkode = ) Values('" + streg + "')";
myCon.Open();
SqlCommand com = new SqlCommand(query, myCon);
Console.WriteLine("navn: "+navn);
SqlDataReader dr = com.ExecuteReader();
if (dr.Read())
{
navn = dr.GetString(1);
}
myCon.Close();
return navn;
}
It throws an exception at com.ExecutiveReader(); and the exception is:
Incorrect syntax near ')'.
I don't know why this one doesn't work right now, because I've used it in another project.
Your query looks like it was copied from something that used to be an INSERT statement; you don't need the VALUES... clause at the end of the statement. Try changing your query to:
string query =
"SELECT Navn FROM Vare WHERE Stregkode = #streg";
Then modify this code to use the parameter:
SqlCommand com = new SqlCommand(query, myCon);
com.Parameters.AddWithValue("#streg", streg);
It doesn't work because your SQL is broken:
SELECT Navn FROM Vare WHERE Stregkode = ) Values('" + streg + "')"
What did you expect that WHERE clause to do, and what values are you trying to use? It looks like you've got a broken copy/paste from an update command.
Additionally, you shouldn't put values into your SQL like that anyway - you should use parameterized queries to avoid SQL injection attacks (and to avoid formatting issues etc).
Ya, surely it will give. Why you put the Values in your select query? which is wrong syntax, Try Now.
string query = "SELECT Navn FROM Vare WHERE Stregkode = '" + streg + "'";
I have the following method to inserting data into an an access databasewhich works fine but I do get a problem if I try to insert text that contains single quotes I have learned.
[WebMethod]
public void bookRatedAdd(string title, int rating, string review, string ISBN, string userName)
{
OleDbConnection conn;
conn = new OleDbConnection(#"Provider=Microsoft.Jet.OleDb.4.0;
Data Source=" + Server.MapPath("App_Data\\BookRateInitial.mdb"));
conn.Open();
OleDbCommand cmd = conn.CreateCommand();
cmd.CommandText = #"INSERT INTO bookRated([title], [rating], [review], [frnISBN], [frnUserName])VALUES('" + title + "', '" + rating + "','" + review + "','" + ISBN + "', '" + userName + "')";
cmd.ExecuteNonQuery();
conn.Close();
}
From what I understand one of the ways to solve the problem is by using parameters. I am not sure how to do this to be honest. How could I change the above code so that I insert the data by using parameters instead?
Same as for any other query:
a) Replace actual hardcoded parameters in your OleDbCommand with placeholders (prefixed with #),
b) Add instances of OleDbParameter to the DbCommand.Parameters property. Parameter names must match placeholder names.
[WebMethod]
public void bookRatedAdd(string title, int rating, string review, string ISBN, string userName)
{
using (OleDbConnection conn = new OleDbConnection(
"Provider=Microsoft.Jet.OleDb.4.0;"+
"Data Source="+Server.MapPath("App_Data\\BookRateInitial.mdb"));
{
conn.Open();
// DbCommand also implements IDisposable
using (OleDbCommand cmd = conn.CreateCommand())
{
// create command with placeholders
cmd.CommandText =
"INSERT INTO bookRated "+
"([title], [rating], [review], [frnISBN], [frnUserName]) "+
"VALUES(#title, #rating, #review, #isbn, #username)";
// add named parameters
cmd.Parameters.AddRange(new OleDbParameter[]
{
new OleDbParameter("#title", title),
new OleDbParameter("#rating", rating),
...
});
// execute
cmd.ExecuteNonQuery();
}
}
}
You have to use Parameter to insert Values. Its is allso a security Issue.
If you do it like that a sql injection could by made.
Try like this:
string ConnString = Utils.GetConnString();
string SqlString = "Insert Into Contacts (FirstName, LastName) Values (?,?)";
using (OleDbConnection conn = new OleDbConnection(ConnString))
{
using (OleDbCommand cmd = new OleDbCommand(SqlString, conn))
{
cmd.CommandType = CommandType.Text;
cmd.Parameters.AddWithValue("FirstName", txtFirstName.Text);
cmd.Parameters.AddWithValue("LastName", txtLastName.Text);
conn.Open();
cmd.ExecuteNonQuery();
}
}
For Microsoft Access the parameters are positional based and not named, you should use ? as the placeholder symbol although the code would work if you used name parameters provided they are in the same order.
See the documentation for OleDbCommand.Parameters Property
Remarks
The OLE DB .NET Provider does not support named parameters for passing parameters to an SQL statement or a stored procedure called by an OleDbCommand when CommandType is set to Text. In this case, the question mark (?) placeholder must be used. For example:
SELECT * FROM Customers WHERE CustomerID = ?
Therefore, the order in which OleDbParameter objects are added to the OleDbParameterCollection must directly correspond to the position of the question mark placeholder for the parameter in the command text.
Be sure to include the expected schema type where the parameter will be used AND the schema length if applicable.
I also recommend you always use using statements around your instances where the type implements IDisposable like the OleDbConnection so that the connection is always closed even if an exception is thrown in the code.
Changed Code:
var connectionStringHere = #"Provider=Microsoft.Jet.OleDb.4.0;Data Source=" + Server.MapPath("App_Data\\BookRateInitial.mdb";
using (var conn = new OleDbConnection(connectionStringHere))
using (var cmd = conn.CreateCommand())
{
cmd.CommandText = "INSERT INTO bookRated ([title], [rating], [review], [frnISBN], [frnUserName]) VALUES(?, ?, ?, ?, ?)";
cmd.Parameters.Add(new OleDbParameter("?", OleDbType.VarChar, 100) { Value = title});
cmd.Parameters.Add(new OleDbParameter("?", OleDbType.Integer) { Value = rating });
cmd.Parameters.Add(new OleDbParameter("?", OleDbType.VarChar, 2000) { Value = review });
cmd.Parameters.Add(new OleDbParameter("?", OleDbType.VarChar, 60) { Value = ISBN });
cmd.Parameters.Add(new OleDbParameter("?", OleDbType.VarChar, 256) { Value = userName });
conn.Open();
var numberOfRowsInserted = cmd.ExecuteNonQuery();
}
May I know what's wrong with my statement? I receive a syntax error. Been trying to find out what's wrong all day. :(
cmd.CommandText = "INSERT INTO LogIn(Username,Password) VALUES('" + AddUsernameTextBox.Text + "','" + AddPasswordTextBox.Text + "')";
cmd.CommandText = "INSERT INTO LogIn([Username],[Password]) VALUES('" + AddUsernameTextBox.Text + "','" + AddPasswordTextBox.Text + "')";
This code will help if the error is due to reserved keywords :- username and password. Please quote the error if this is not the case .
command.CommandText = "INSERT INTO Login([Username],[Password]) VALUES(#Username, #Password)";
//Not sure how you create your commands in your project
//here I'm using the ProviderFactory to create instances of provider specific DbCommands.
var parameter = dbProviderFactory.CreateParameter();
parameter.DbType = System.Data.DbType.String;
parameter.ParameterName = "#Username";
parameter.Value = AddUsernameTextBox.Text;
command.Parameters.Add(parameter);
parameter = dbProviderFactory.CreateParameter();
parameter.DbType = System.Data.DbType.String;
parameter.ParameterName = "#Password";
parameter.Value = AddPasswordTextBox.Text;
command.Parameters.Add(parameter);
Below is a more complete code sample of using ConnectionStringSettings and DbProviderFactory etc. This is not going to solve your problem, but this is the way to do data access if you're using ADO.NET core as you seem to be doing in your sample.
ConnectionStringSettings connectionStringSettings = ConfigurationManager.ConnectionStrings["SomeConnectionName"];
if (connectionStringSettings == null)
throw new Exception("Application config file does not contain a connectionStrings section with a connection called \"SomeConnectionName\"");
DbProviderFactory dbProviderFactory = DbProviderFactories.GetFactory(connectionStringSettings.ProviderName);
using (var dbConnection = dbProviderFactory.CreateConnection())
{
dbConnection.ConnectionString = connectionStringSettings.ConnectionString;
dbConnection.Open();
using (var command = dbConnection.CreateCommand())
{
command.CommandText = "INSERT INTO Login([Username],[Password]) VALUES(#Username, #Password)";
var parameter = dbProviderFactory.CreateParameter();
parameter.DbType = System.Data.DbType.String;
parameter.ParameterName = "#Username";
parameter.Value = AddUsernameTextBox.Text;
command.Parameters.Add(parameter);
parameter = dbProviderFactory.CreateParameter();
parameter.DbType = System.Data.DbType.String;
parameter.ParameterName = "#Password";
parameter.Value = AddPasswordTextBox.Text;
command.Parameters.Add(parameter);
var dbTransaction = dbConnection.BeginTransaction();
try
{
command.ExecuteNonQuery();
dbTransaction.Commit();
}
catch (Exception)
{
dbTransaction.Rollback();
throw;
}
}
}
the app.Config file that the code above relies on would look like this the following. Of course only the connectionStrings section in the config file is important in this context
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<connectionStrings>
<add name="SomeConnectionName" providerName="System.Data.OleDb" connectionString="Your Provider Specific Connection String" />
</connectionStrings>
</configuration>
The Best way is to use Parameters: '#'
By this your code will look much more clearer and easy to understand. And makes your Application more secure.
try this code:
using (var con = new OleDbConnection(_constring))
{
con.Open();
using (
var cmd =
new OleDbCommand(
"UPDATE LogIn SET Username=#Username, Password=#Password WHERE (ID = #Id)",
con))
{
try
{
cmd.Parameters.AddWithValue("#Username",EditUsernameTextBox.Text);
cmd.Parameters.AddWithValue("#Password",EditPasswordTextBox.Text);
cmd.Parameters.AddWithValue("#Id",IDTextBox.Text);
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
throw;
}
finally
{
con.Close();
}
}
Regards!
Please protect the single quotes. Also, you may need a closing semicolon in the Access SQL string.
cmd.CommandText = "INSERT INTO LogIn(Username,Password) VALUES('" + AddUsernameTextBox.Text.Replace("'","''") + "','" + AddPasswordTextBox.Text.Replace("'","''") + "');";
It is of course only 100% better to use parameterized queries; from you other questions is this C#/Visual Studio against MS Access through OLE/Jet?
Is ID column an integer? If not you need to wrap values in single quotes, too.
Also, try removing the parentheses.
Most likely, the value in IDTextBox.text is not numeric...
But like Daniel points out, this is very vulnerable to SQL inject..
What would happen if I typed:
' ; DROP TABLE login
in the EditUserNameTextBox field
Check if this works. You were missing single quotes for the value in your WHERE statement:
"UPDATE
LogIn
SET
Username = '" + EditUsernameTextBox.Text + "'
,Password = '" + EditPasswordTextBox.Text + "'
WHERE
(ID = '" + IDTextBox.Text + "')";
Plus, make sure, as Daniel White mentioned, you take care of any SQL Injection.
You missed a pair of apostrophes, if your ID is non-numeric:
WHERE (ID ='" + IDTextBox.Text + "')";
Do the values of EditUsernameTextBox.Text or EditPasswordTextBox.Text themselves have quotes? This will bollix up the SQL.
If so, you'll need to escape them. or don't use string concatenation as pointed out already...
And have you printed the statement out to see what it looks like as requested...?