Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a library for sanitizing query parameters for PostgreSQL or SQL in general, for FreePascal and Delphi?

I got bitten my first sql escaping error (it was long overdue) when I tried to execute the PostgreSQL query below with a value containing an apostrophe eg. O'Brien, using FreePascal and Lazarus

SQL.Add(format('select * from zones where upper(zn_name) >=  %s and upper(zn_name) < %s order by zn_name',[sQuote(zoneMin), sQuote(zoneMax)]));

In the query above SQuote is a function that wraps a string in single quotes. Is there some standard library for sanitizing SQL query parameters for Lazarus/FreePascal or Delphi for that matter?

like image 659
vfclists Avatar asked Nov 01 '12 04:11

vfclists


1 Answers

Your application is vulnerable to a serious class of security problems called SQL injection. See http://bobby-tables.com/.

Sure, O'Brian causes an error, but what about ');DROP SCHEMA public;-- ? Or ');DELETE FROM users;-- ? The 1st shouldn't work because your app should never run as a superuser or the user that owns the tables, but few application designers make the effort to actually do that and often run privileged users in production. The 2nd will work in most applications; see the end of the post for details.

The easiest and best preventative measure is to use parameterized statements* in your client library. See this example for Delpi:

To use a prepared statement, do something like this:

query.SQL.Text := 'update people set name=:Name where id=:ID';
query.Prepare;
query.ParamByName( 'Name' ).AsString := name;
query.ParamByName( 'ID' ).AsInteger := id;
query.ExecSQL;

(I've never used Delphi and last wrote Pascal code in 1995; I'm just quoting the example given).

What you are doing currently is string interpolation of parameters. It is very dangerous. It can be done safely only if you have a robust function for quoting SQL literals, one that doesn't just bang quotes on each end, but also handles other escapes, quote doubling, etc. It is the approach of last resort; it's strongly preferable to use a parameterized statement.


Here's an expansion of the example I gave above. Say you're doing a perfectly ordinary insert of a user by username, where 'Fred' is an example username input by the client:

INSERT INTO users ( user_name ) VALUES ('Fred');

Now some unpleasant person sends the username ');DELETE FROM users;--. Suddenly your application is running:

INSERT INTO users ( user_name ) VALUES ('');DELETE FROM users;--');

which when expanded is:

INSERT INTO users ( user_name ) VALUES ('');
DELETE FROM users;
--');

or in other words an insert that inserts an empty string (though they could just as easily put a perfectly valid username in), followed by a DELETE FROM users; statement - deleting all rows in users - then a comment that does nothing. Splat. There goes your data.


* Parameterized statemments are sometimes incorrectly referred to as prepared statements. That's incorrect because a prepared statement isn't necessarily parameterized, and a parameterized statement isn't necessarily prepared. The confusion has arisen because the database interfaces of many languages don't provide a way to use parameterized statements without also using prepared statements.

like image 107
Craig Ringer Avatar answered Oct 16 '22 03:10

Craig Ringer