Secure full where statement when it comes as a string - c#

I have the following C# function
SomeFunction(string table, string column, string where) {
Sql sql = new Sql("SELECT ");
// [...] validate table and column values
sql.Append(column);
sql.Append(" FROM ");
sql.Append(table);
sql.Append(" WHERE ");
sql.Append(where); // This is the issue
}
As you can see this is awful, I'm dealing with this very old legacy code and changing the function signature and the way the clients use it is just not feasible. What I have to do is secure the 'where' clause. This clause may contain any number of conditions and data types.
I had a bunch of ideas but I don't think they are a good solution, I think this requires a properly written and tested code, but if I do it myself out of the blue it'll probably have holes. Here are some thoughts:
Splitting the string by char '=' -> what if that's not the condition operator
Find if string contains semicolons -> the SELECT clause remains vulnerable, and maybe one of the conditions contains that char so it'd give a false positive
If you have any idea/suggestion/pointing in the right direction I will be most grateful.

If the where clause is currently based on being a pre-composed string, then frankly I don't think it is a viable approach to attempt to "secure" it. It is theoretically possible, but any attempt at parsing the SQL will fail if the composed and compromised (injected) where clause is legitimate (but abusive). At that point: you've already lost track of the original intent. That's kinda the entire point of SQL injection: the resultant SQL is valid SQL - so it is very hard for you to tell the difference between where Name = 'Fred Orson' -- check name (probably fine) and where Name = 'Fred' Or 1=1 --' (injected - query widening).
So: while I acknowledge that you say:
changing the function signature and the way the clients use it is just not feasible.
Not changing the function signature doesn't really help you solve the problem. Trying to detect certain patterns is just an arms race, where you need to win every time and the attacker needs to win only once.
If it was me, I'd be doing something like:
[Obsolete("Please specify parameters separately - use 'null' if no parameters are needed")]
SomeFunction(string table, string column, string where) {
return SomeFunction(table, column, where, null);
}
SomeFunction(string table, string column, string where, object args) {
// ...
}
and using an approach like "Dapper" uses to compose the parameters from the args parameter - or just use "Dapper" itself to run the query, and use that functionality for free.
This approach:
prevents new uses of the dangerous API being added
lets the existing code continue to work for now
but lets you track how many outstanding problem calls there are, by watching the warnings
Edit: note: the point of the args parameter is to allow the caller to parameterize their inputs, i.e.
string name = ...
var users = SomeFunction("Users", "Id", "Name=#name", new { name });
With SomeFunction decomposing args and adding parameter name/value pairs from the properties on args (if it is non-null). There are various approaches to composing parameter sets, but the approach shown here is simple and easy to implement correctly - which makes it a clear win for me.

Related

How do I get SimpleMembershipProvider extended properties back from database like FirstName and LastName?

Following this post, SimpleMemberShipProvider, Using multiple PropertyValues with custom Database tables, I successfully create a new user using the SimpleMembershipProvider and WebMatrix.WebData.WebSecurity.
WebSecurity.CreateUserAndAccount(model.UserName, model.Password,new { FirstName = model.FirstName,LastName = model.LastName,AppId = Guid.NewGuid(), MemberId = model.MemberId});
However, I have not been able to find any built-in methods for retrieving this information back from MembershipProvider or WebSecurity methods. I know I could query the database directly to get the information back and update, but then my code would become tightly coupled with this test implementation.
Anyone know how to get extended properties from a currently logged in user in the SimpleMembershipProvider? Thanks.
SBirthare is right, however, since he doesn't explain how to do this, allow me (this is assuming you use the C# server-side language option, which you tagged, so I believe you do. This also assumes that the table name in which the "FirstName" and "LastName" columns belong is, in fact, "UserProfile"):
Since WebMatrix comes with SQL Server-CE, we can just use a simple SQL query for this.
First set up your connection to the database:
var db = Database.Open("Users");
Next, compile the appropriate string to be used for the query (a simple string variable is used):
string selectQueryString = "SELECT FirstName, LastName FROM UserProfile";
The above string when passed to the Query() C# method (shown below), will however return a list (specifically IEnumerable<dynamic>) of all "FirstName"s and "LastName"s returned from the database. If you only wanted certain rows returned you can use the WHERE clause in the SQL string, so instead of the above string you could make this instead (this is just an example, you will have to tailor your own conditions to fit your situation, but this should give you an easy example):
string selectQueryString = "SELECT FirstName, LastName FROM UserProfile WHERE Email = #0 AND UserID = #1";
First let me address what the #0 and the #1 is, in case you don't already know. They are placeholders that will end up being filled with the conditions you want to test against (more on this further down) using this method, known as "paramaterized queries", this will be your smoking gun against SQL injection attacks. In short: ALWAYS USE THIS METHOD FOR CONDITIONS TESTED IN THE WHERE CLAUSE (I really can't stress this enough).
Now, I'm not sure how much you know about SQL querying, but they can be very powerful and useful and by using things like LIKE, ORDER BY, GROUP BY, JOIN, UNION, AND, OR, or even subqueries, as well as, many many other keywords and approaches, you can really make the SQL query return just about anything you desire, in the order you desire (a great beginner SQL query tutorial can be found here: http://www.sqlcourse.com/index.html).
Okay, moving on... Once you've written the selectQueryString the way that you want to, all you need left is to store it, like so:
int ID = 6;
string email = "testEmailName#gmail.com";
var queryResultsList = db.Query(selectQueryString, email, ID); //Here the first argument passed to the `db.Query()` method is the query string, but each additional argument passed (and you can actually pass an array of values here instead if you want) is used to fill the `#0` and `#1` placeholders you formed in your string earlier (order is ever important here!).
And display it, like so:
foreach (var row in queryResultsList)
{
//Do something for each row returned, here!
<div>FIRST NAME: #row.FirstName</div><br/>
<div>LAST NAME: #row.LastName</div>
{
Sorry if this is a lot to take in, but I thought I would at least show you all of the steps that you need to actually make this happen. Really there isn't that much to it, I just felt like giving you a bunch of helpful pointers a long the way :)
Anyway, just let me know if you have any questions or if I need to clarify anything.
EDIT:
Well, I just saw that you use MVC as opposed to Web-Pages. My answer is from the Web-Pages environment, but to be honest, I'm not sure if it would be any different or not because I have never worked with MVC. Either way, the SQL query itself should be the same and since we're both using C#, idk.
Either way, if I am told that this answer doesn't fit the scenario or is not useful to you, I will be glad to delete it.
As far as I know you will have to query the table using your current ORM framework.
SimpleMembershipProvider and WebSecurity allows you basic stuff e.g. WebSecurity.CurrentUserName, WebSecurity.UserExists, WebSecurity.GetUserId, etc.
The custom column you add into any of the tables created by SimpleMembershipProvider have to be fetched manually from the table.
SimpleMembershipProvider have no idea that you added FirstName and LastName into UserProfile (or other table) table.

dealing with special characters in parameter values for LIKE comparisons

Suppose I'm querying a Sql Server DB for row count based on a LIKE comparison on a column whose value is supplied via windows form text input. Using parameters here is important due to possible user input leading to injection. Eventually I'm to execute member function ExecuteScalar() on an instantiated SqlCommand object I named cmd, but first I've to add the parameter. For example:
cmd.Parameters.AddWithValue("#param1", textBox1.Text);
Sql Server uses the special character % as a wildcard match for the LIKE comparison. What I wanted to do was allow the user to use * for wildcards instead. Hence, a simple replace:
textBox1.Text.Replace('*','%');
The problem is I run into issues with values containing special symbols % and _. One way to search for a literal % rather than use it as a wildcard is to enclose it in square brackets: [%].
So, now my replace has to become:
textBox1.Text.Replace("%","[%]").Replace("_","[_]").Replace('*','%');
Order is important here as well, since if the last Replace were made sooner the % would be treated incorrectly.
I'm not sure I've covered all my bases, are there other characters I need to worry about here? Does this really protect from injection? Is there some other preferred way of doing this?
An example query might be something like this:
SELECT COUNT(*) FROM [MyTable] WHERE [Column1] = #param1
Where MyTable is your table name, and Column1 is a valid column name within MyTable. We can assume that Column1 is some nvarchar type.
You shouldn't really need anything else, but I'd make sure to test oddball things from user input. Some characters you haven't accounted for have special meaning in LIKE:
^
-
Since you're passing a parameter into the statement and not blindly appending the string, there should be little danger of injection, but you may want to try variations of user input such as:
foo'; DELETE dbo.[UnimportantTable];
foo''; DELETE dbo.[UnimportantTable];
foo''''; DELETE dbo.[UnimportantTable];
Again, I'm not sure if you're vulnerable because I can't see the whole thing, but I do think it's very easy to construct a variety of tests so that you know all of the potential outcomes with a wide sampling of potential inputs.
As #Bryan pointed out, certainly a good way to limit the risk is to connect using a login that has very explicit read-only permissions only on the objects you want them to be able to read. Then even if they do exploit some hole in your scaffolding, getting in doesn't buy them much.

Escaping various characters in C# SQL from a variable

I'm working a C# form application that ties into an access database. Part of this database is outside of my control, specifically a part that contains strings with ", ), and other such characters. Needless to say, this is mucking up some queries as I need to use that column to select other pieces of data. This is just a desktop form application and the issue lies in an exporter function, so there's no concern over SQL injection or other such things. How do I tell this thing to ignore quotes and such in a query when I'm using a variable that may contain them and match that to what is stored in the Access database?
Well, an example would be that I've extracted several columns from a single row. One of them might be something like:
large (3-1/16" dia)
You get the idea. The quotes are breaking the query. I'm currently using OleDb to dig into the database and didn't have an issue until now. I'd rather not gut what I've currently done if it can be helped, at least not until I'm ready for a proper refactor.
This is actually not as big problem as you may see it: just do NOT handle SQL queries by building them as plain strings. Use SqlCommand class and use query parameters. This way, the SQL engine will escape everything properly for you, because it will know what is the code to be read directly, and what is the parameter's value to be escaped.
You are trying to protect against a SQL Inject attack; see https://www.owasp.org/index.php/SQL_Injection.
The easiest way to prevent these attacks is to use query parameters; http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlparameter.aspx
var cmd = new SqlCommand("select * from someTable where id = #id");
cmd.Parameters.Add("#id", SqlDbType.Int).Value = theID;
At least for single quotes, adding another quote seems to work: '' becomes '.
Even though injection shouldn't be an issue, I would still look into using parameters. They are the simpler option at the end of the day as they avoid a number of unforeseen problems, injection being only one of them.
So as I read your question, you are building up a query as a string in C#, concatenating already queried column values, and the resulting string is either ceasing to be a string in C#, or it won't match stuff in the access db.
If the problem is in C#, I guess you'll need some sort of escaping function like
stringvar += escaped(columnvalue)
...
private static void escaped(string cv) as string {
//code to put \ in front of problem characters in cv
}
If the problem is in access, then
' escapes '
" escapes "
& you can put a column value containing " inside of '...' and it should work.
However my real thought is that, the SQL you're trying to run might be better restructured to use subqueries to get the matched value(s) and then you're simply comparing column name with column name.
If you post some more information re exactly what the query you're producing is, and some hint of the table structures, I'll try and help further - or someone else is bound to be able to give you something constructive (though you may need to adjust it per Jet SQL syntax)

How can I sort an SQLite query ignoring articles ("the", "a", etc.)?

I'm using C# to display a list of movie titles that I am calling from an SQLite database. Currently, I'm using a custom ListBox class that has a function to sort the text stripping the word 'The' from the beginning of every item. However, it doesn't exactly seem to be the simplest way to do it, since it calls from the SQLite database and then sorts. I'd prefer to cut it down to just one step, hopefully sorting straight from the database in my "SELECT" query.
I've done some searching on this, and have found some suggestions, including creating an extra sort-by column in the database. While this is certainly a possibility, I'm wondering if there's any simpler options that don't require inserting almost identical duplicate information (especially if the database becomes larger). I'm pretty new to SQLite, but I've read something about creating a collate function that can be used to create custom ordering. However, I'm not sure if this is appropriate use for it and can't seem to find any help with implementing it in C#.
Was hoping someone might be able to share some guidance. If an extra sorting column is the best way to go, then that is what I shall do.
To avoid inserting duplicate data, what about having two columns: TITLE_PREFIX (usually empty, but sometimes contains "The ", or "A "; no index on this column) and TITLE (contains the title without "The " or "A "; this is the column you create the index on). To display the data, you have to combine TITLE_PREFIX and TITLE. But you just search on TITLE.
Here is the solution:
ORDER BY (CASE
WHEN sortTitle LIKE 'the %' THEN substr(sortTitle,5)
WHEN sortTitle LIKE 'a %' THEN substr(sortTitle,3)
WHEN sortTitle LIKE 'an %' THEN substr(sortTitle,4)
ELSE sortTitle END)
You could store each title in 2 parts: title and prefix.
With SQLite you can combine 2 string values via the || operator also known as the concatenate operator.
Here's an example:
SELECT prefix || ' ' || title FROM movies ORDER BY title
You can also use ltrim in case prefix is empty, so you don't have a space at the front:
SELECT ltrim(prefix || ' ' || title) FROM movies ORDER BY title
Another alternative is to store the prefix at the end of the title. For example at a lot of movie stores you will see something like:
Three Musketeers, The
Within C# Code
If you wanted to do this within C#, use LINQ to do the ordering for you. I've posted a full sample on PasteBin. This will allow you to:
avoid duplicating data in your database
take advantage of DB indexes as you normally would, no matter which RDBMS
put in noise words in a config file, thereby reducing downtime/rebuild/redeploy when modifying the list
ensure a solution is more readable in your client code
DropDownList1.DataSource = myBooks.OrderBy(n => ReplaceNoise(n.Title))
public string ReplaceNoise(string input)
{
string[] noise = new string[] { "the", "an", "a" };
//surely this could be LINQ'd
foreach (string n in noise)
{
if (input.ToLower().StartsWith(n))
{
return input.Substring(n.Length).Trim();
}
}
return input;
}
Within your SQLite statement
How about simply replacing the noise words with blanks in the order by? It's an ugly first step, but strongly consider a new column to store this value for sorting purposes.
ORDER BY REPLACE(REPLACE([title],'the',''), 'a', '')
Admittedly, this gets ugly when you end up with this:
REPLACE(REPLACE(REPLACE(REPLACE([title],'The ',''),'a',''),'of',''),'by','')
You could try building a table that supports full-text searching (using the FTS module) on the title. Then you'll be able to do fast searches on any words in the title without requiring lots of extra work on your part. For example, a user query of good bad ugly might produce “The Good, the Bad and the Ugly” as one of its first results. The extra cost of all this is about a quarter of the length of the text itself in general, but might be more for your dataset, as titles aren't full english text. You also need to spend the time building those extra indices – you don't want to build them on your main dataset on a live system (obviously) – but that shouldn't be too big a problem.
Create a virtual column (result of a function that can be implemented in C#) and sort on this virtual column. The function could move "The" to the end as in "Three Musketeers, The" or discard "The", whatever you want it to do.

Regex to Extract Update Columns from a Sql Statement

I need a Regex Statement (run in c#) that will take a string containing a Sql Update statement as input, and will return a list of columns to be updated. It should be able to handle columns surrounded by brackets or not.
// Example Sql Statement
Update Employees
Set FirstName = 'Jim', [LastName] = 'Smith', CodeNum = codes.Num
From Employees as em
Join CodeNumbers as codes on codes.EmployeeID = em.EmployeeID
In the end I would want to return an IEnumerable or List containing:
FirstName
LastName
CodeNum
Anyone have any good suggestions on implementation?
Update: The sql is user-generated, so I have to parse the Sql as it is given. The purpose of extracting the column names in my case is to validate that the user has permission to update the columns included in the query.
You're doing it backwards. Store the data in a broken out form, with the table to be updated, the column names, and the expressions to generate the new values all separate. From this canonical representation, generate both the SQL (when you need it) and the list of columns being updated (when you need that instead).
If you absolutely must pull the column names out of a SQL statement, I don't think that regular expressions are the correct way to go. For example, in the general case you may need to skip over new value expressions that contain arbitrarily nested parenthesis. You will probably want a full SQL parser. The book Lex & Yacc by Levine, Mason, and Brown has a chapter on parsing SQL.
Response to update:
You are in for a world of hurt. The only way to do what you want is to fully parse the SQL, because you also need to make sure that you don't have any subexpressions that perform unauthorized actions.
I very, very strongly recommend that you come up with another way to do whatever it is that you are doing. Maybe break out the modifiable fields into a separate table and use access controls? Maybe come up with another interface for them to use in specifying what they want done? Whatever it is that you're doing, there is almost certainly a better way to do it. Down that path there be dragons.
Regular expressions cannot do this task, because SQL is not a regular language.
You can do this, but not with a regular expression. You need a full-blown parser.
You can use ANTLR to generate parsers in C#, and there are free grammars available for parsing SQL in ANTLR.
However, I agree with Glomek that allowing user-supplied SQL to be run against your system, even after you have tried to validate that it includes no "unauthorized actions," is foolish. There are too many cases that may circumvent your validation.
Instead, if you have only a single text field, you should define a simplified Domain-Specific Language that permits users to specify only actions that they are authorized to do. From this input, you can build the SQL yourself.
SQL has a complex recursive grammer, and, there will always be some sub select, group by, or literal that will break your regex based parser.
Why don't use a sql parser to achieve what you need, here is an article shows you how to achieve what you need within 3 minutes.

Categories