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.
Related
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}";
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
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.
I've got a bit of a poor situation here. I'm stuck working with commerce server, which doesn't do a whole lot of sanitization/parameterization.
I'm trying to build up my queries to prevent SQL Injection, however some things like the searches / where clause on the search object need to be built up, and there's no parameterized interface.
Basically, I cannot parameterize, however I was hoping to be able to use the same engine to BUILD my query text if possible. Is there a way to do this, aside from writing my own parameterizing engine which will probably still not be as good as parameterized queries?
Update: Example
The where clause has to be built up as a sql query where clause essentially:
CatalogSearch search = /// Create Search object from commerce server
search.WhereClause = string.Format("[cy_list_price] > {0} AND [Hide] is not NULL AND [DateOfIntroduction] BETWEEN '{1}' AND '{2}'", 12.99m, DateTime.Now.AddDays(-2), DateTime.Now);
*Above Example is how you refine the search, however we've done some testing, this string is NOT SANITIZED.
This is where my problem lies, because any of those inputs in the .Format could be user input, and while i can clean up my input from text-boxes easily, I'm going to miss edge cases, it's just the nature of things. I do not have the option here to use a parameterized query because Commerce Server has some insane backwards logic in how it handles the extensible set of fields (schema) & the free-text search words are pre-compiled somewhere. This means I cannot go directly to the sql tables
What i'd /love/ to see is something along the lines of:
SqlCommand cmd = new SqlCommand("[cy_list_price] > #MinPrice AND [DateOfIntroduction] BETWEEN #StartDate AND #EndDate");
cmd.Parameters.AddWithValue("#MinPrice", 12.99m);
cmd.Parameters.AddWithValue("#StartDate", DateTime.Now.AddDays(-2));
cmd.Parameters.AddWithValue("#EndDate", DateTime.Now);
CatalogSearch search = /// constructor
search.WhereClause = cmd.ToSqlString();
It sounds like you'll have to go old school and validate the data yourself before constructing the query. I'm not a .NET guy but in the CGI world I would sanitize the input with something like:
$foo =~ s/[^a-zA-Z0-9*%]//g
That will thwart any SQL injection I can think of and still allow wildcards. Only problem is the regexs are expensive.
In SQL one can write a query that searches for a name of a person like this:
SELECT * FROM Person P WHERE P.Name LIKE N'%ike%'
This query would run with unicode characters (assuming that the Name column and database were setup to handle unicode support).
I have a similar query in HQL that is run by Hibernate (NHibernate). The generated query looks like:
SELECT P FROM SumTotal.TP.Models.Party.Person P join P.Demographics PD WHERE (PD.LastName LIKE '%カタカ%' )
Unfortunately, placing a 'N' in front of the literal in the HQL results in an error. I've tried escaping the unicode characters in the string and still no success.
The database is accepting and saving unicode characters from Hibernate. I've been able to successfully populate an object with a unicode string, save it with Hibernate, and verify it in the database. It would seem to me as a little odd that I cannot use unicode strings in custom queries (or I'm also assuming named queries).
Is this a known issue or limitation of Hibernate (Nhibernate)? How do you use unicode in HQL?
Several sites suggest using the Criteria queries. Due to constraints in the framework that I'm working in, this is not possible.
Have you tried with parameters:
IList<Person> people = session
.CreateQuery("from Person p where p.Name like :name")
.SetParameter("name", "%カタカ%")
.List<Person>();
They also have the advantage to protect your query against SQL injection.
I found a solution that works. I highly doubt it is the best solution. It is however the solution that I'm going to implement until I can authorize a rewrite of the entire query building section of the software that I'm working on.
In the instance:
SELECT P FROM SumTotal.TP.Models.Party.Person P join P.Demographics PD WHERE (PD.LastName LIKE '%カタカ%')
The where clause contains this literal:
'%カタカ%'
This literal can be broken up into nchars which Hibernate (Nhibernate) will unknowingly pass through to the SQL it generates. Odd, but it works. Thus the previous query could be written as:
SELECT P FROM SumTotal.TP.Models.Party.Person P join P.Demographics PD WHERE (PD.LastName LIKE '%' + nchar(0x30AB) + nchar(0x30BF) + nchar(0x30AB)+ '%')
This solution is far from optimal because it would require going through each character and determining if it was a multibyte character. However, in the case of where this code lives in its app it is used in a dynamic query generator that processes multiple different criteria under different operations. In the example I give it is looking for unicode anywhere in the string. It is possible that this function may be returning the where clause portion for a column equaling a specific numeric value or it could be looking for the starting characters of a string. The method that builds the operator uses a operator type and the term to hand back a string. I could rewrite that but it would be a large task. The above fix will allow me to process a string passed into this method. I offer this solution because it does work, but darin's answer is probably the best way I could find.
This problem arises because NHibernate tries to access the column without the type length. Hence in the HBM.xml its very important to mention length for Legacy databases otherwise it will fail for UNIcode related stuff.
Thanks,
Thani