Mysql change delimiter for better SQL INJECTION handling? - sql

I am using mysql and trying to block unwanted queries injection of people who will try to use my single query to run several ones. ie, for example when i have the parameter "?id=3", people can try to run it with ="id=3;drop table users"
Now, i know that the best way to avoid this is by parsing and checking the parameter, but is there a way to change the concatenated queries delimiter from ";" to something like "%^#$%##$^$"?

Security through obscurity is useless. Take the time to write the proper code to protect against the SQL injection attacks. Doing it up front will cost you a lot less than doing it after you've had a successful attack run against your code!

The best way to defend against injection attacks is to use Prepared Statements.
By using Prepared Statements, you are immune to most injection attacks (which of course aren't the only security vulnerability you need to think about, but they're a pretty major one.)

The statement DELIMITER configuration is a built-in command only in the mysql client tool. You can't change the delimiter for multi-statements. It's always semicolon.
Also, the MySQL API allows execution of only one statement at a time, by default. The example you're talking about doesn't work unless you explicitly enable multi-statements.
Furthermore, multi-statements isn't the only vector for SQL injection. Even if you could change the statement delimiter, it wouldn't do anything to protect against SQL injection that modifies a single given statement.
UPDATE Accounts SET PASSWORD = '...' WHERE account_id = $id
In this example, if $id has a value of "1234 OR 1=1" then the attacker has changed the password for all accounts, including probably a privileged user. And yet no multi-statements were involved.
You still need to be mindful of security issues when you write code. There's no silver bullet to protect against SQL injection.
Even query parameters aren't a cure-all for SQL injection. Parameters take the place only of values in SQL expressions. There are many common cases where it's still necessary to interpolate application variables into an SQL string. For example, when parameterizing an IN() predicate, or when choosing ORDER BY expressions. Don't listen to people who say prepared queries are 100% proof against security flaws.
See also my presentation SQL Injection Myths and Fallacies, or the chapter on SQL Injection in my book, SQL Antipatterns Volume 1: Avoiding the Pitfalls of Database Programming.

When you call mysql_query or mysql_real_query, it won't run multiple statements anyway, so the statement delimiter doesn't really matter. You can enable multiple statements per query when you connect, but since you're trying to avoid that ability, simply don't enable it.
An even better option for avoid SQL injection is to use prepared statements. Start with mysql_stmt_init and mysql_stmt_prepare with placeholders for your statement's parameters, and then fill in the parameters with mysql_stmt_bind_param before mysql_stmt_execute. If you're not calling the API directly, then whatever wrapper library you have should also provide support for prepared statements. (If it doesn't support them, then consider switching to a better wrapper.)

Related

SQL Injection Prevention Method

If I wrapped an explain around a sql statement i.e.
explain ( [arbitrary sql string] )
I should be able to prevent injections of create, drop, truncate, delete commands correct?
I've only tried this on postgres and it seems to work, but I don't know if there's a corner case that I forgot.
Nope. It won't work. You could still end up with something like this:
Explain( select columns from table where value = '');injected sql here --)
All you've done is make the attacker do just a very little bit of extra work to figure out they also need the ) character in addition to the usual single quote.
If you want to prevent Sql injection, make sure you always use parameterized queries.
You need in general :
1/ Validate the data you need with a whitelist approach. Do not blacklist characters or other things
2/ use Parametrized queries
3/ Don't use dynamic query anytime

Preventing sql injection - why should one escape the input if using prepared statements?

I am doing some research in web security, and the reviser of my article said:
"It should be clear that to avoid SQL Injection, the application should use prepared statements, stored procedures and escape input"
My question is: Is one of these methods isn't enough? Ok, prepared statements or stored procedures are better than a simple escape, but if I use PDO, why i should escape the input or have a stored procedure? Does this make sense?
I would change the reviser's wording to:
It should be clear that to avoid SQL Injection, the application should use prepared statements, escape input, or filter application data before interpolating into an SQL string.
It's not necessary to escape a value if you're going to pass as a parameter. In fact, you should not, because you'll insert literal backslashes into your data.
You need to interpolate strings into your SQL statement when you can't use a query parameter. Examples include:
Table names and column names, which have their own syntax for delimited identifiers. These must be part of the SQL query at prepare time, so the RDBMS can parse and validate them.
SQL keywords, which should be sanitized but cannot be escaped because they are not delimited.
Other syntax or expressions.
Some cases where literal values must be provided at prepare time, e.g. MySQL's fulltext functions do not support parameters for the search pattern.
Stored procedures are not a defense against SQL injection. You can prepare and execute unsafe dynamic SQL statements inside a stored procedure. See http://thedailywtf.com/Articles/For-the-Ease-of-Maintenance.aspx for a great story about that.
I cover all these cases in my presentation SQL Injection Myths and Fallacies. That may be a helpful resource for you.
I also cover SQL injection defense in a chapter of my book, SQL Antipatterns Volume 1: Avoiding the Pitfalls of Database Programming.
If i use PDO, why i should [es]scape the input or have a stored procedure?
As long as you always use PDO, I don't see a reason to bother with input escaping or SPs.
When in doubt, ask yourself: will this piece of plain input data be escaped by some API down the line? Most of the time they will, except when you manually build SQL sentences from input data.
You should not escape if you use PDO. You should not escape if you use JDBC Prepared Statements with parameters. Similarly, most other APIs also take care of this. Stored procedures are not even concerned with escaped data and using them will not magically avoid SQL injection security issues if the input data is not escaped in the SQL that runs the procedure.
Always SQL-Escape data that you put in SQL sentences. Never SQL-Escape data outside SQL sentences.

Dynamic SQL Within A Stored Procedure Security

I've got the SQL stored procedure from hell that I've created and all input parameters are parameterised for security but it's not running as quick as I'd like so I wanted to make it dynamic and so a bit more efficient.
I know I can keep my input parameters to my stored procedure, then within it create a dynamic SQL statement into which I can then pass the input parameters of the stored procedure, but are there any security implications I need to be aware of when doing this? I'm guessing not as it just another set of parameters and they should be treated the same as the parameters passed to the current stored procedure.
Obviously, producing code like this "WHERE OrderNo = ' + #orderno is asking for trouble - I will be doing 'WHERE OrderNo = #orderno' in the dynamic SQL, but is there anything else I need to be aware of?
Thx MH
PS - before anyone suggests it, I can't create the SQL dynamically at the client side using LINQ or similar - it all (for various reasons) has to be contained and controlled at the database level
There is a form of SQL injection that many people don't think about when doing dynamic SQL in stored procedures: SQL Truncation attacks.
With a SQL truncation attack, the attacker injects a long peace of text making the used text variable overflow and lose part of the query.
This article gives more information about this.
Where your parameters are always Data Items, both when being passed to the StoredProc and when used in yor DynamicSQL, everything will stay safe.
Should any of your StoredProc's parameters end up being table or field names, and so forming part of the structure of the DynamicSQL itself, you introduce a new risk : That the parameter can be used to inject rogue SQL Code.
To prevent against such an injection attack you should always validate any such parameters.
One example of how to do this would be to use the input parameter as a token, rather than substitute it directly into the DynamicSQL...
SET #SQL = #SLQ + CASE targetTable WHEN '1' THEN 'table1'
WHEN 'tx' THEN 'tableX'
END
Some people suggest you only need to validate on the client application. But that means that if someone becomes able to execute you SP's directly, the SP has become a point of attack. I always prefer to validate both on the client AND in the server.
EDIT Performance
Note that using DynamicSQL isn't always a guarnatee of performance increases. If you use parameterised queries, the execution plans can indeed be stored. But if the queries do vary greatly, you may still find a significant overhead in compiling the SQL.
There is also the fact that dependancy tracking is lost. It's not possible to see what tables the SP is dependant on, because the code is hidden away as strings.
I have very rarely found that DynamicSQL is needed. Often a complex query can be reformed as several optimised queries. Or the data can be re-structured to meet the new demands. Or even a rethink of both the data and the algorithm using the data. One might even be able to suggest that a dependancy on DynamicSQL is an indicator of another underlying problem.
Perhaps it's not in the scope of your question, but it would be interesting to see the actual puzzle you're facing; to see if anyone has any alternative approaches for you.

PDO prepare statements: Do we need to escape?

public function receiveDomainNames($keyword)
{
try
{
$stmt = $this->_dbh->prepare("SELECT d.someField FROM domain d WHERE d.someField LIKE :keyword");
$someField = '%'.$keyword.'%';
Do we need to escape $keyword on this case?
On php manual we can read:
If an application exclusively uses prepared statements, the developer can
be sure that no SQL injection will
occur (however, if other portions of
the query are being built up with
unescaped input, SQL injection is
still possible).
Is this the case on your opinion, are, on this case, build up unescaped input (no prior treatment has been made to our $keyword parameter) ?
Thanks in advance,
MEM
Given the above SQL statement, I see no rational possibility of a SQL injection.
What the warning about "other parts" would be a SQL query like:
$binds = array(":id"=>$_GET['id']);
$myPDO->prepare("SELECT {$_GET['columns']} FROM {$_GET{['table']} WHERE id = :id");
$statement = $myPDO->execute($binds);
The example is a worst case/explicit example of what they mean, that naively someone might think since they're escaping the where argument, that everything is safe.
With your example above, there is no un-escaped input so you're safe.
If an application exclusively uses prepared statements, the developer
can be sure that no SQL injection will occur (however, if other
portions of the query are being built up with unescaped input, SQL
injection is still possible).
I'd figure variables you create shouldn't have to be escaped because you know what they're doing.
Only escape content gotten from the user, such as $_COOKIE, $_POST, $_GET and other parameters such as the URL.

How much sanitizing is needed for Web Services that call Stored Procedures?

I am building a series of web services in VB.Net
Each of the web services takes multiple string values, performs some validation/processing then calls a Stored Procedure using Linq to SQL. Some of the string contains user data that is stored in the database:
These string values passed from the web service are escaped to trap single quote characters, semi colons and the various bracket types.
I am calling the SP using the datacontext.spname(parameter1, parameter2) method.
The aim is to ensure that the web services are as resilient as possible, while still being performant.
Have I done enough to prevent SQL injection attacks?
Usually you are good, but there are a few caveats:
Careful of stored procs that use sp_executesql or exec. You can pass in a query in the param and end up executing it.
Careful with LIKE sections of queries cause they can be widened with % if likened to a param.
Fields used in webpages may need some extra processing before being sent in, to avoid cross site scripting. (which you should also defend against when pulling information out)
I know for a fact that LINQ to SQL queries all the data send to the database via SQL parameters -- which keeps you safe from SQL injection. I'm not entirely sure, but since LINQ abstracts the stored procedure, it too most likely passes the arguments to the stored procedures in the same manner.
What does that mean? You don't have to worry about sanitizing your data because LINQ will take care of it. You could of course test it out with a simple SQL injection type attack -- something like a harmless insert or select.
If you're using parameters then you don't need to sanitise at all as single quotes and the other sql injection nasties get escaped for you.
It's probably a bad idea to sanitise on input depending on the data you're storing. If you're storing things that end up embedded in a web page and you encode/sanitise them on data entry what happens if your sanitation code has a bug? You end up with data in the database that will cause problems on output and no easy way to fix it without an update over all your data. It's better to sanitise when you output data as corrections to the sanitation code will then run against all data. You also have the advantage of easier searching in SQL should that be a concern.
I'd limit the web service to obvious things, null and range checks.