How could I go about entering data such as "John's shoe" into a SQL Server CE table (version 3.5) as the insert statements and so forth do not accept the use of the ' apostrophe in a statement such as the following statement:
INSERT INTO ShowsDB(Item) VALUES('+ "John's shoes" + "')
You must avoid putting your data directly into your SQL, basically. Use parameterized SQL instead:
// I'm assuming you're opening the connection already
string sql = "INSERT INTO ShowDB(ITEM) VALUES (#Name)";
using (var command = new SqlCommand(sql, connection))
{
command.Parameters.Add("#Name", SqlDbType.NVarChar).Value = "John's shoes";
command.ExecuteNonQuery();
}
Using parameterized SQL has three benefits:
Avoids SQL injection attacks
Avoids unnecessary and dangerous string conversions (particularly for date/time types)
Separates the "code" (SQL) from the data (parameters) which makes it easier to understand
Standard SQL escaping is that quotes should be doubled, so your query becomes
INSERT INTO ShowsDB(Item) VALUES('+ "John''s shoes" + "')
Which is perfectly fine for things like running SELECT statements against a copy of the DB to diagnose problems, but should NEVER be used in actual production systems. Parameterized queries are your friend.
Related
The following piece of code is being highlighted as a security vulnerability to SQL injection attacks.
StringBuilder sb = new StringBuilder();
sb.Append("DROP DATABASE IF EXISTS " + dbname);
String **sqlCommText** = sb.ToString();
using (SqlCommand command = new SqlCommand(**sqlCommText**, connection))
{
connection.Open();
Namely the sqlCommText
I'm aware of creating prepared statements on DML sql like insert and updates but i dont think this works on DDL sql - i cant parameterize the dbname into the sql.
Any suggestions how this should be fixed?
Preventing SQL Injection here is pretty easy: query the names of all of the databases on the SQL Server like this:
SELECT name, QUOTENAME(name) as QName
FROM sys.databases
WHERE database_id > 4;
Then, before you execute the rest of your SQL code, just check that your dbname variable is in that list of names returned by the query and if it is, then use the corresponding QName in your query (this protects against odd characters in the database name and also against something called latent injection).
However, as I mentioned in the comments, stopping injection is the easy problem. The hard problem here is to make sure that that legitimate users do not accidentally drop the wrong database, and worse, that bad actors do not intentionally drop the wrong database(s).
This question already has answers here:
How can I add user-supplied input to an SQL statement?
(2 answers)
Closed 7 years ago.
I have to program an application management system for my OJT company. The front end will be done in C# and the back end in SQL.
Now I have never done a project of this scope before; in school we had only basic lessons about SQL. Somehow our teacher completely failed to discuss SQL injections, something which I have only now come in contact with by reading about it on the net.
So anyway my question is: how do you prevent SQL injections in C#? I vaguely think that it can be done by properly masking the text fields of the application so that it only accepts input in a specified format. For example: an e-mail textbox should be of the format "example#examplecompany.tld". Would this approach be sufficient? Or does .NET have pre-defined methods that handle stuff like this? Can I apply a filter to a textbox so it only accepts email-address format or a name textbox so it doesn't accept special chars?
By using the SqlCommand and its child collection of parameters all the pain of checking for sql injection is taken away from you and will be handled by these classes.
Here is an example, taken from one of the articles above:
private static void UpdateDemographics(Int32 customerID,
string demoXml, string connectionString)
{
// Update the demographics for a store, which is stored
// in an xml column.
string commandText = "UPDATE Sales.Store SET Demographics = #demographics "
+ "WHERE CustomerID = #ID;";
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlCommand command = new SqlCommand(commandText, connection);
command.Parameters.Add("#ID", SqlDbType.Int);
command.Parameters["#ID"].Value = customerID;
// Use AddWithValue to assign Demographics.
// SQL Server will implicitly convert strings into XML.
command.Parameters.AddWithValue("#demographics", demoXml);
try
{
connection.Open();
Int32 rowsAffected = command.ExecuteNonQuery();
Console.WriteLine("RowsAffected: {0}", rowsAffected);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
My answer is quite easy:
Use Entity Framework for communication between C# and your SQL database. That will make parameterized SQL strings that isn't vulnerable to SQL injection.
As a bonus, it's very easy to work with as well.
SQL injection can be a tricky problem but there are ways around it. Your risk is reduced your risk simply by using an ORM like Linq2Entities, Linq2SQL, NHibrenate. However you can have SQL injection problems even with them.
The main thing with SQL injection is user controlled input (as is with XSS). In the most simple example if you have a login form (I hope you never have one that just does this) that takes a username and password.
SELECT * FROM Users WHERE Username = '" + username + "' AND password = '" + password + "'"
If a user were to input the following for the username Admin' -- the SQL Statement would look like this when executing against the database.
SELECT * FROM Users WHERE Username = 'Admin' --' AND password = ''
In this simple case using a paramaterized query (which is what an ORM does) would remove your risk. You also have a the issue of a lesser known SQL injection attack vector and that's with stored procedures. In this case even if you use a paramaterized query or an ORM you would still have a SQL injection problem. Stored procedures can contain execute commands, and those commands themselves may be suceptable to SQL injection attacks.
CREATE PROCEDURE SP_GetLogin #username varchar(100), #password varchar(100) AS
DECLARE #sql nvarchar(4000)
SELECT #sql = ' SELECT * FROM users' +
' FROM Product Where username = ''' + #username + ''' AND password = '''+#password+''''
EXECUTE sp_executesql #sql
So this example would have the same SQL injection problem as the previous one even if you use paramaterized queries or an ORM. And although the example seems silly you'd be surprised as to how often something like this is written.
My recommendations would be to use an ORM to immediately reduce your chances of having a SQL injection problem, and then learn to spot code and stored procedures which can have the problem and work to fix them. I don't recommend using ADO.NET (SqlClient, SqlCommand etc...) directly unless you have to, not because it's somehow not safe to use it with parameters but because it's that much easier to get lazy and just start writing a SQL query using strings and just ignoring the parameters. ORMS do a great job of forcing you to use parameters because it's just what they do.
Next Visit the OWASP site on SQL injection https://www.owasp.org/index.php/SQL_Injection and use the SQL injection cheat sheet to make sure you can spot and take out any issues that will arise in your code. https://www.owasp.org/index.php/SQL_Injection_Prevention_Cheat_Sheet finally I would say put in place a good code review between you and other developers at your company where you can review each others code for things like SQL injection and XSS. A lot of times programmers miss this stuff because they're trying to rush out some feature and don't spend too much time on reviewing their code.
SQL injection should not be prevented by trying to validate your input; instead, that input should be properly escaped before being passed to the database.
How to escape input totally depends on what technology you are using to interface with the database. In most cases and unless you are writing bare SQL (which you should avoid as hard as you can) it will be taken care of automatically by the framework so you get bulletproof protection for free.
You should explore this question further after you have decided exactly what your interfacing technology will be.
I follow the syntax of
INSERT INTO Table1
VALUES (value1, value2, value3…)
This has worked fine so far. But now I have some values that contain normal English text like "I'm going home". The ' character ruins the SQL command in C#. I have written the following:
command.CommandText = "INSERT INTO Bio VALUES ('" + name + "','"I'm going home" + "');
evaluates to
INSERT INTO Bio VALUES ('Peter','I'm going home')
which obviously will not work. How do I make sure special character will not ruin the SQL statements?
Use SqlParameter for heaven's sake. Otherwise your program will be vulnerable to SQL Injection. It will also solve your problem with the special characters.
Learn about parameterized queries for your provider. They exists for Odbc, OleDb, Sql, etc.
command.CommandText = "INSERT INTO Bio Values (#name, #text)";
command.Parameters.Add(/* appropriate param type for your provider */); // add for #name, #text, etc.
// execute query
Use two single quotes whenever there is a single quote you want to escape
Also instead of building your queries like this, you should use parameterized queries in a language of your choice. Escaping the characters yourself opens the door for SQL Injections.
Usually you can escape a single quote by screening with another one.
For example the following is a valid statement
INSERT INTO myTable (Column1) VALUES ('Hello I''m Jack');
However I suggest you using parameters.
command.CommandText = "INSERT INTO Bio VALUES (#Name, #OtherValue)";
command.Parameters.AddWithValue("Name", name);
command.Parameters.AddWithValue("OtherValue", "I'm going home");
One addition point in favor of using parameters is that you are free from burden of formatting and other stuff. I mean date values, uniqueidentifiers, etc.
I do use
HttpUtility.HtmlEncode(text)
It makes all that SQL injection stuff disappear, and it seems easier than to use parameters.
Don't forget to use
HttpUtility.HtmlDecode(text)
to get your input back in the form you received it
For example, this is the code that I am using:
String commandString = "UPDATE Members SET UserName = #newName , AdminLevel = #userLevel WHERE UserID = #userid";
using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["sqlconnectionstring"].ConnectionString))
{
SqlCommand cmd = new SqlCommand(commandString, conn);
cmd.Parameters.Add("#newName", newName);
cmd.Parameters.Add("#userLevel", userLevel);
cmd.Parameters.Add("#userid", userid);
conn.Open();
cmd.ExecuteReader();
Reader.Close();
}
That code looks fine. Parameterisation is the way to go, as opposed to concatenating user-supplied values in an adhoc SQL statement which can open you up to sql injection attacks. This can also help with execution plan reuse.
The only thing I'd add, is I prefer to explicitly define the datatype and sizes of the parameters. For example, if you don't then, as an example, all string values will get passed in to the database as NVARCHAR instead of VARCHAR. Hence I like to be explicit.
It's safe against SQL injection because it's parameterized. Other security concerns, such as ensuring that #userid is not spoofed, are separate security concerns that should be dealt with in other layers of your application.
That's still a static query string. It's not really "dynamic" sql until you also build parts of the string on the fly — something like this:
var sql = "SELECT columns FROM Table WHERE 1=1";
if (!string.IsNullOrEmpty(txtName.Text)) sql += " AND Name LIKE '%' + #Name + '%'";
if (!string.IsNullOrEmpty(txtDesc.Text)) sql += " AND CONTAINS(DESCRIPTION, #description)";
But even so, this is still "safe" in the sql injection sense as long as you continue to use parameters for every part of the query that originates with user input.
.NET, Java and other high level database API's in various language often provide techniques known as prepared statements and parameter binding as opposed to sending plain text commands to the Database server. What I would like to know is what happens when you execute a statement like this:
SqlCommand cmd = new SqlCommand("GetMemberByID");
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter param = new SqlParameter("#ID", memberID);
para.DbType = DbType.Integer;
cmd.Parameters.Add(param);
I know this is a best practice. SQL injection attacks are minimized this way. But what exactly happens under the hood when you execute these statements? Is the end result still a SQL safe string? If not, what is the end result? And is this enough to prevent SQL injection attacks?
The MySQL manual page on prepared statements provides lots of information (which should apply to any other RDBMS).
Basically, your statement is parsed and processed ahead of time, and the parameters are sent separately instead of being handled along with the SQL code. This eliminates SQL-injection attacks because the SQL is parsed before the parameters are even set.
in layman terms: if a prepared statement is sent then the DB will use a plan if it is available, it doesn't not have to recreate a plan every time this query is sent over but only the values of the params have changed. this is very similar to how procs work, the additional benefit with procs is that you can give permission through procs only and not to the underlying tables at all
If you're using MS SQL, load up the profiler and you'll see what SQL statements are generated when you use parameterised queries. Here's an example (I'm using Enterprise Libary 3.1, but the results are the same using SqlParameters directly) against SQL Server 2005:
string sql = "SELECT * FROM tblDomains WHERE DomainName = #DomName AND DomainID = #Did";
Database db = DatabaseFactory.CreateDatabase();
using(DbCommand cmd = db.GetSqlStringCommand(sql))
{
db.AddInParameter(cmd, "DomName", DbType.String, "xxxxx.net");
db.AddInParameter(cmd, "Did", DbType.Int32, 500204);
DataSet ds = db.ExecuteDataSet(cmd);
}
This generates:
exec sp[underscore]executesql N'SELECT * FROM tblDomains WHERE DomainName = #DomName AND DomainID = #Did',
N'#DomName nvarchar(9),
#Did int',
#DomName=N'xxxxx.net',
#Did=500204
You can also see here, if quotation characters were passed as parameters, they are escaped accordingly:
db.AddInParameter(cmd, "DomName", DbType.String, "'xxxxx.net");
exec sp[underscore]executesql N'SELECT * FROM tblDomains WHERE DomainName = #DomName AND DomainID = #Did',
N'#DomName nvarchar(10),
#Did int',
#DomName=N'''xxxxx.net',
#Did=500204