Avoiding SQL injection in Web API query string parameters - asp.net-web-api

We have an ASP.NET Web API controller that accepts a comma-delimited string of database column names from the query string. This string of column names is checked to ensure only alpha characters, underscores, and commas are present in the string; no spaces, special characters or numbers allowed. This string is eventually added to a SQL statement via string interpolation exactly as passed to the API in the query string.
Any other query string parameters are added to the SQL statement as parameters. We encountered an issue with parameterizing a list a columns not be interpreted correctly by Oracle so we ended up with this solution.
Although not ideal, are there any additional steps to prevent SQL injection attacks via this vector?
We are currently using Dapper for data access but frequently use plain ADO.NET.

If that's the only thing you can do, as long as you make sure you don't allow numbers and special characters like quotes, equal and different you will be fine. I would even say you should be good with numbers, I have seen cases where numbers are actually used as part of column names so you could relax that restriction a little.
You could basically create a white list of characters allowed and when the request comes in, if any character is not part of that list then you can throw Bad Request and stop right there. A white list is much better than a black list as it can be much shorter and it's easier to maintain.
Another layer of protection can come from the API itself. Make sure you :
authenticate the access to your controller, no anonymous users allowed, maybe something like OAUTH2 if you can.
turn that API call into a POST and send the list of columns in the body of the request not in the query string.
issue the request over HTTPs.
All these things together should keep you well protected as no one can now watch and see what you are sending through and they can't issue their requests either if you protect your endpoint properly.

Related

Purpose of web app input validation for security reasons

I often encounter advice for protecting a web application against a number of vulnerabilities, like SQL injection and other types of injection, by doing input validation.
It's sometimes even said to be the single most important technique.
Personally, I feel that input validation for security reasons is never necessary and better replaced with
if possible, not mixing user input with a programming language at all (e.g. using parameterized SQL statements instead of concatenating input in the query strings)
escaping user input before mixing it with a programming or markup language (e.g. html escaping, javascript escaping, ...)
Of course for a good UX it's best to catch input that would generate errors on the backand early in the GUI, but that's another matter.
Am I missing something or is the only purpose to try to make up for mistakes against the above two rules?
Yes you are generally correct.
A piece of data is only dangerous when "used". And it is only dangerous if it has special meaning in the context it is used.
For example, <script> is only dangerous if used in output to an HTML page.
Robert'); DROP TABLE Students;-- is only dangerous when used in a database query.
Generally, you want to make this data "safe" as late as possible. Such as HTML encoding when output as HTML to an HTML page, and parameterised when inserting into a database. The big advantage of this is that when the data is later retrieved from these locations, it will be returned in its original, unsanitized format.
So if you have the value A&B O'Leary in an input field, it would be encoded like so:
<input type="hidden" value="A& O'Leary" />
and if this is submitted to your application, your programming framework will automatically decode it for you back to A&B O'Leary. Same with your DB:
string name = "A&B O'Leary";
string sql = "INSERT INTO Customers (Name) VALUES (#Name)";
SqlCommand command = new SqlCommand(sql);
command.Parameters.Add("#Name", name];
Simples.
Additionally if you then need to give the user any output in plain text, you should retrieve it from your DB and spit it out. Or in JavaScript - you just JavaScript entity encode (although best avoided for complexity reasons - I find it easier to secure if I only output to HTML then read the values from the DOM).
If you'd HTML encoded it early, then to output to JavaScript/JSON you'd first have to convert it back then hex entity encode it. It will get messy and some developers will forget they have to decode first and you will have &amps everywhere.
You can use validation as an additional defence, but it should not be the first port of call. For example, if you are validating a UK postcode you would want to whitelist the alphanumeric characters in upper and lower cases. Any other characters would be rejected or removed by your application. This can reduce the chances of SQLi or XSS occurring on your application, but this method falls down where you need inputs to include characters that have special meaning to your output context (" '<> etc). For example, on Stack Overflow if they did not allow characters such as these you would be preventing questions and answers from including code snippets which would pretty much make the site useless.
Not all SQL statements are parameterizable. For example, if you need to use dynamic identifiers (as opposed to literals). Even whitelisting can be hard, sometimes it needs to be dynamic.
Escaping XSS on output is a good idea. Until you forget to escape it on your admin dashboard too and they steal all your admin's cookies. Don't let XSS in your database.

Validating FirstName in a web application

I do not want to be too strict as there may be thousands of possible characters in a possible first name
Normal english alphabets, accented letters, non english letters, numbers(??), common punctuation synbols
e.g.
D'souza
D'Anza
M.D. Shah (dots and space)
Al-Rashid
Jatin "Tom" Shah
However, I do not want to except HTML tags, semicolons etc
Is there a list of such characters which is absolutely bad from a web application perspective
I can then use RegEx to blacklist these characters
Background on my application
It is a Java Servlet-JSP based web app.
Tomcat on Linux with MySQL (and sometimes MongoDB) as a backend
What I have tried so far
String regex = "[^<>~##$%;]*";
if(!fname.matches(regex))
throw new InputValidationException("Invalid FirstName")
My question is more on the design than coding ... I am looking for a exhaustive (well to a good degree of exhaustiveness) list of characters that I should blacklist
A better approach is to accept anything anyone wants to enter and then escape any problematic characters in the context where they might cause a problem.
For instance, there's no reason to prohibit people from using <i> in their names (although it might be highly unlikely that it's a legit name), and it only poses a potential problem (XSS) when you are generating HTML for your users. Similarly, disallowing quotes, semi-colons, etc. only make sense in other scenarios (SQL queries, etc.). If the rules are different in different places and you want to sanitize input, then you need all the rules in the same place (what about whitespace? Are you gong to create filenames including the user's first name? If so, maybe you'll have to add that to the blacklist).
Assume that you are going to get it wrong in at least one case: maybe there is something you haven't considered for your first implementation, so you go back and add the new item(s) to your blacklist. You still have users who have already registered with tainted data. So, you can either run through your entire database sanitizing the data (which could take a very very long time), or you can just do what you really have to do anyway: sanitize data as it is being presented for the current medium. That way, you only have to manage the sanitization at the relevant points (no need to protect HTML output from SQL injection attacks) and it will work for all your data, not just data you collect after you implement your blacklist.

How to do SQL injection on Oracle

I'm doing an audit of a system, which the developers insist is SQL injection proof. This they achieve by stripping out the single-quotes in the login form - but the code behind is not parameterized; it's still using literal SQL like so:
username = username.Replace("'", "");
var sql = "select * from user where username = '" + username + "'";
Is this really secure? Is there another way of inserting a single quote, perhaps by using an escape character? The DB in use is Oracle 10g.
Maybe you can also fail them because not using bind variables will have a very negative impact on performance.
A few tips:
1- It is not necessarily the ' character that can be used as a quote. Try this:
select q'#Oracle's quote operator#' from dual;
2- Another tip from "Innocent Code" book says: Don't massage invalid input to make it valid (by escaping or removing). Read the relevant section of the book for some very interesting examples. Summary of rules are here.
Have a look at the testing guide here: http://www.owasp.org/index.php/Main_Page That should give you more devious test scenarios, perhaps enough to prompt a reassessment of the SQL coding strategy :-)
No, it is not secure. SQL injection doesn't require a single-quote character to succeed. You can use AND, OR, JOIN, etc to make it happen. For example, suppose a web application having a URL like this: http://www.example.com/news.php?id=100.
You can do many things if the ID parameter is not properly validated. For example, if its type is not checked, you could simply use this: ?id=100 AND INSERT INTO NEWS (id, ...) VALUES (...). The same is valid for JOIN, etc. I won't teach how to explore it because not all readers have good intentions like you appear to have. So, for those planning to use a simple REPLACE, be aware that this WILL NOT prevent an attack.
So, no one can have a name like O'Brian in their system?
The single quote check won't help if the parameter is numeric - then 1; DROP TABLE user;-- would cause some trouble =)
I wonder how they handle dates...
If the mechanism for executing queries got smart like PHP, and limited queries to only ever run one query, then there shouldn't be an issue with injection attacks...
What is the client language ? That is, we'd have to be sure exactly what datatype of username is and what the Replace method does in regard to that datatype. Also how the actual concatenation works for that datatype. There may be some character set translation that would translate some quote-like character in UTF-8 to a "regular" quote.
For the very simple example you show it should just work, but the performance will be awful (as per Thilo's comment). You'd need to look at the options for cursor_sharing
For this SQL
select * from user where username = '[blah]'
As long as [blah] didn't include a single quote, it should be interpreted as single CHAR value. If the string was more than 4000 bytes, it would raise an error and I'd be interested to see how that was handled. Similarly an empty string or one consisting solely of single quotes. Control characters (end-of-file, for example) might also give it some issues but that might depend on whether they can be entered at the front-end.
For a username, it would be legitimate to limit the characterset to alphanumerics, and possibly a limited set of punctuation (dot and underscore perhaps). So if you did take a character filtering approach, I'd prefer to see a whitelist of acceptable characters rather than blacklisting single quotes, control characters etc.
In summary, as a general approach it is poor security, and negatively impacts performance. In particular cases, it might (probably?) won't expose any vulnerabilities. But you'd want to do a LOT of testing to be sure it doesn't.

How to prevent injections in ASP/VBScript?

What are the best ways (or at least most common ways) in ASP (VBScript) for input handling? My main concerns are HTML/JavaScript injections & SQL injections. Is there some equivalent to PHP's htmlspecialchars or addslashes, et cetera? Or do I have to do it manually with something like string replace functions?
The bottom line is this:
Always HTML-encode user input before you write it to your page. Server.HTMLEncode() does that for you.
Always use parameterized queries to interface with a database. The ÀDODB.Command and ADODB.CommandParameter objects are the right choice here.
Always use the URLScan utility and IIS lockdown on the IIS server that renders the page, unless they are version 6 and up, which do not require these tools anymore.
If you stick to points 1 and 2 slavishly, I can't think of much that can go wrong.
Most vulnerabilities come from not properly encoding user input or building SQL strings from it. If you for some reason come to the point where HTML-encoding user input stands in your way, you have found a design flaw in your application.
I would add to Tomalaks list one other point.
Avoid using concatenation of field values in SQL code. That is, in some cases a stored procedure may build some SQL in a string to subsequently execute. This is fine unless a textual field value is used as part of its construction.
A command parameter can protect SQL code designed to input a value from being hijacked into executing unwanted SQL but it allows such unwanted SQL to become data in the database. This is a first-level vunerability. A second-level injection vunerability exists if the field's value is then used in some SQL string concatenation inside a stored procedure.
Another consideration is that this is just minimal protection. All its doing is rendering attack attempts harmless. However in many cases it may be better to add to this a system which prevents such data entry altogther and/or alters admins to a potential injection attack.
This is where input validation becomes important. I don't know of any tools that do this for you but a few simple Regular Expressions might help. For example, "<\w+" would detect the attempt to include a HTML tag in the field.

Do you validate your URL variables?

When you're passing variables through your site using GET requests, do you validate (regular expressions, filters, etc.) them before you use them?
Say you have the URL http://www.example.com/i=45&p=custform. You know that "i" will always be an integer and "p" will always contain only letters and/or numbers. Is it worth the time to make sure that no one has attempted to manipulate the values and then resubmit the page?
Yes. Without a doubt. Never trust user input.
To improve the user experience, input fields can (and IMHO should) be validated on the client. This can pre-empt a round trip to the server that only leads to the same form and an error message.
However, input must always be validated on the server side since the user can just change the input data manually in the GET url or send crafted POST data.
In a worst case scenario you can end up with an SQL injection, or even worse, a XSS vulnerability.
Most frameworks already have some builtin way to clean the input, but even without this it's usually very easy to clean the input using a combination of regular exceptions and lookup tables.
Say you know it's an integer, use int.Parse or match it against the regex "^\d+$".
If it's a string and the choices are limited, make a dictionary and run the string through it. If you don't get a match change the string to a default.
If it's a user specified string, match it against a strict regex like "^\w+$"
As with any user input it is extremely important to check to make sure it is what you expect it is. So yes!
Yes, yes, and thrice yes.
Many web frameworks will do this for you of course, e.g., Struts 2.
One important reason is to check for sql injection.
So yes, always sanitize user input.
not just what the others are saying. Imagine a querystring variable called nc, which can be seen to have values of 10, 50 and 100 when the user selects 10, 50 and 100 results per page respectively. Now imagine someone changing this to 50000. If you are just checking that to be an integer, you will be showing 50000 results per page, affecting your pageviews, server loads, script times and so on. Plus this could be your entire database. When you have such rules (10, 50 or 100 results per page), you should additionaly check to see if the value of nr is 10, 50 or 100 only, and if not, set it to a default. This can simply be a min(nc, 100), so it will work if nc is changed to 25, 75 and so on, but will default to 100 if it sees anything above 100.
I want to stress how important this is. I know the first answer discussed SQL Injection and XSS Vulnerabilities. The latest rave in SQL Injection is passing a binary encoded SQL statement in query strings, which if it finds a SQL injection hole, it will add a http://reallybadsite.com'/> to every text field in your database.
As web developers we have to validate all input, and clean all the output.
Remember a hacker isn't going to use IE to compromise your site, so you can't rely on any validation in the web.
Yes, check them as thoroughly as you can. In PHP I always check the types (IsInt(i), IsString(p)).

Resources