HttpUtility.UrlEncode to prevent SQL inject - c#

was using HttpUtility.UrlEncode() to prevent SQL injection on where clauses. However some of the text being input has spaces and replacing them with %20 will stop the query. Is there a better alternative?

Use parameters in your database queries rather than concatenating input. Job done. If that sounds like a lot of work - consider tools like dapper that make it easy:
string name = ...
int regionId = ...
var customers = connection.Query<Customer>(
"select * from Customers where Name = #name and RegionId = #regionId",
new { name, regionId }).AsList();

To prevent SQL Injection it is preferred to use SQL Parameters.
When working with parameters SQL ensures that the parameters in the query are never executed.
Never construct queries by concatenating strings. Especially when it is input that is untrusted (Received from a user)!
In your case using c# you can take a look here:
http://csharp-station.com/Tutorial/AdoDotNet/Lesson06

Related

What's the best way to organize SQL queries?

We have a couple of SQL queries as strings:
public class Query
{
public static string CreditTransferId(string expectedValue, string table, int statusId, int messageTypeId, int destination103, int destination202, string StoreStatus202Id)
{
return $"SELECT top 1 Id from {table} where MessageId = '{expectedValue}' and FlowId=3 and StatusId={statusId} and MessageTypeId={messageTypeId} and " +
$" Destination103={destination103} and Destination202={destination202} and StoreStatus103Id is null and StoreStatus202Id {StoreStatus202Id}";
}
}
We have them returned as strings from methods inside the Query class. We want to refactor the code, since we have a method with more than 3 parameters which is pretty hard to use.
How would you go about this? What's the cleanest way to organize SQL queries which need a lot of parameters?
Dynamic SQL is a very bad thing for a start as these are open to SQL injection, you should use parameterise queries and return a string.
"eg: SELECT top 1 Id from [Table] where [MessageId] = #messageId" etc
So you dont need to pass in any values, you would add these to your list of SqlParamater's
The table name is probably pointless as this is related to the sql, so probably just add that into the sql string
This doesn't really need an extra class, just create the sql variable where you call it, so it right there if you need it?
..or use Stored Procedures
..or use Entity Framework
EF is great and you have to decide if that's what you want. There are some cases where it is not suitable. Of u decide to stick with plain text queries how about dividing queries into parts:
FromBuilder
JoinBuilder
GroupBuilder
Condition builder etc
ex.:
return #"
"+new TableIdSelectorBuilder(table).Get() +#"
"+new FromBuilder().Get(table) +#"
"+new TableConditionByIdBuilder(table).Get(I'd)+#"
";
EDIT:
Stored procedures allow to change queries without publishing new app version but is a bit pain in the ass to work on a living organism. At least sometimes.
Hopefully this helps you a bit. I was figuring this out a long time ago too.
Use nameOf instead of hardcoded column names
One advice that I have is: Try to use nameOf() for column names (in case your domain model matches exactly your database structure).
Refactoring becomes a lot easier as well.
Create a query builder
I created a class which allows me to create simple to medium complex queries (Select, Insert, Update, Joins, Deletes, Limit, Offset, ...). For most of the queries that I write I can use this query builder to get what I need and the code will look something like this:
var query = new QueryBuilder()
.Update(nameof(MyTable))
.Set(nameof(MyTable.Name), entity.Name)
.Set(nameof(MyTable.Firstname), entity.Firstname)
.WhereEquals(nameof(MyTable.Id), entity.Id)
.Build();
Unfortunately, I haven't found a good QueryBuilder out there yet. Therefore I created my own.
Use string literals
Microsoft Documentation
Another solution that I recently encountered is by doing the following:
var query = $$"""
SELECT * FROM {{nameof(MyTable)}
WHERE
XX
""";
This at least allows you to indent correctly and the code will remain clean.
Outsource your queries in separate files
I was also thinking about having bigger queries in separate files and include them in the Assembly. When you want to execute the query, you load the query from the file and run it like this.
You might also want to cache that query then, to not always load it from the file.
Final words
Personally, I try to use the QueryBuilder as often as possible. It creates clean code which looks somewhat like LINQ
Backup approach for me is to use the string literals as showed above
Trying to create separate files for queries, I have never tried yet, because there was no use for myself
I would also avoid using Stored Procedures, because they are pain to write and also hard to debug in my opinion
The cleanest option would be to use Entity Framework, but if you want to use Micro-ORMs like Dapper, try one of the solutions above

Is there any reason to use string.Format() with just a string parameter?

I'm currently updating some old code at work. I ran into a number of lines where string.Format() is used for seemingly no reason. I'm wondering if there is some use for using string.Format() without additional parameters, but I can't think of any.
What's the difference between this:
string query = String.Format(#"select type_cd, type_shpmt from codes");
and this:
string query = "select type_cd, type_shpmt from codes";
I also don't think that the # is needed since it doesn't need to be a string literal, and it's not a multi-line string.
Cut and paste failures. Someone didn't take the time to cleanup the code. There is no reason to use string.Format. Simply delete it and assign directly.
⚠️ Warning ⚠️
If the person is using the Format to combine parameters be wary; one should use the SQLCommand and SQLParameter class to avoid sql injection.
While Format should be deleted, spare # and make query being more readable:
string query =
#"select type_cd,
type_shpmt
from codes";
If you want to modify table, field names etc. (which you can't do via Sql Parameters) try using string interpolation:
string myTableName = "codes";
...
string query =
$#"select type_cd,
type_shpmt
from {myTableName}";

Is there any restriction to WindowsInstaller msi database queries in sql

I am trying to run some sql queries on my msi database in c#.But it seems like some specific sql queries are not working.
WindowsInstaller.Installer ins = (WindowsInstaller.Installer)new Installer();
string strFileMsi = #"abc.msi";
Database db3 = ins.OpenDatabase(strFileMsi, WindowsInstaller.MsiOpenDatabaseMode.msiOpenDatabaseModeDirect);
string q = "SELECT File FROM File WHERE FileName LIKE '%s%'";
WindowsInstaller.View vw = db3.OpenView(q);
vw.Execute(null);
string q2="SELECT * FROM InstalExecuteSequece ORDER BY Sequence DESC"
WindowsInstaller.View vw2 = db.OpenView(q2);
vw.Execute(null);
If i run the same query without DESC keyword and all,it works fine.Similarly is the case with LIKE KEYWORD also.All of these gives sql exception.
Windows Installer implements a subset of SQL described in SQL Syntax. Within that subset there are several limitations, including three that I'll highlight here:
There is no support for DESC or LIKE, and ORDER BY may not handle strings as you expect
Update queries cannot modify a value in a primary key column
There is no way to escape the apostrophe character ' in a SQL query. If you need to match a string value like 'It's', you have to use the a question mark ? placeholder in the query and pass a record containing the value to view.Execute(record)
To overcome the limited capabilities of installer supported SQL, you can make use of the Microsoft.Deployment.WindowsInstaller.Linq assembly which is shipped with wix. To extract the last sequence number of the InstalExecuteSequece table for example, you'd simply write the following query:
var db = session.Database.AsQueryable( );
var lastSequence = db.ExecuteIntegerQuery( "SELECT `Sequence` FROM `InstalExecuteSequece` ORDER BY `Sequence`" ).Last( );

Querying Numeric TableName fails

I am able to query the table named "012012" within SQL, but when attempting to query it from a C# application, it will say incorrect syntax near '012012'. Within SQL I would use double quotes to query this table as it doesn't work without them. Here is the code I am using:
string query = string.format("SELECT rec FROM '"+012012+"' WHERE cust = 'custname';");
If you're using SQL Server, then it does not allow un-escaped identifiers to start with numbers. So, you must use brackets like so [012012]. However, this is only part of your problem. The other part is that you are trying to use a numeric literal, and convert it to a string, but this number starts with a 0. This will get truncated by default and just become 12012. So, your best bet is to just do this:
string query = string.format("SELECT rec FROM [{0:D6}] WHERE cust = 'custname';", 012012);
The {0:D6} tells string.format to make the decimal field 6 characters wide, and pad 0's if it's shorter (which it would otherwise be 5 characters).
In this case, however, you probably don't even need to do that.. unless you actually need to derive the table name from a number, and you can just do this:
string query = "SELECT rec FROM [012012] WHERE cust = 'custname';";
I would also strongly advise against even starting to write code like this, as it is prone to SQL Injection vulnerability, you should always use parameterized queries and prepared statements. They're more work, but they are far safer.
Learning to write SQL code like this will form bad habits, which can be very dangerous later in your career.
You can't have a table name as '012012'. You don't even to use string.Format in your case. It will be useless.
If you wanna use string.Format with your table name, you can do it like;
string query = string.format("SELECT rec FROM [{0}] WHERE cust = 'custname';", "012012");
Try using square brackets:
string query = string.format("SELECT rec FROM ["+012012+"] WHERE cust = 'custname';");
Brackets are required if you use keywords or special chars in the column names or identifiers.

SQL Injection Technique For Query String

I've been trying to ensure my code isn't susceptible to the infamous SQL Injection Attack. The question involves the Query String, the legacy code I'm managing has instances of inline SQL which applies:
string query = #"SELECT * FROM [Order]
WHERE ([Id]=" + Request.QueryString[#"oid"] + ");";
Obviously that is bad, it will take the attack. My question is this enough?
command.Parameters.AddWithValue("#OrderId", Request.QueryString[#"oid"]);
So now the query has a parameter, which is being passed a value. I know it has some form of encoding. However, will that be enough as any malicious attacker could exploit that query string? So should I do Encode on the query string? That way it will encode it safely to avoid being exploited any further?
Some clarification on the matter would be helpful.
is this enough?
No - you also need to change your query to
string query = #"SELECT * FROM [Order]
WHERE ([Id]=#OrderId);";
I know it has some form of encoding
No, it uses the actual value, but it does not inject it into the SQL statement. It treats it as a literal string, so there's no way to include punctuation or malicious code that will get interpreted as SQL.
EDIT
I may have misunderstood - you may need to URL-decode the value if it included URL-encoded characters (%20, &, etc. ), but no encoding (or decoding) is necessary to prevent SQL injection.

Categories