views:

697

answers:

7

Hello

I would like to know if I'm safe against SQL injection when I use something like that with PostgresSQL:

CREATE or REPLACE FUNCTION sp_list_name( VARCHAR )
RETURNS SETOF v_player AS '
   DECLARE
      v_start_name ALIAS FOR $1;
      r_player  v_player%ROWTYPE;
      v_temp VARCHAR;
   BEGIN
      v_temp := v_start_name || ''%'';
      FOR r_player IN
         SELECT first_name, last_name FROM v_player WHERE last_name like v_temp
      LOOP
         RETURN NEXT r_player;
      END LOOP;
      RETURN;
   END;
' LANGUAGE 'plpgsql' VOLATILE;

I want to use this function to list player's name beginning with a letter.

select * from sp_list_name( 'A' );

gives me players with last name beginning with A.

I tried to inject sql with

select * from sp_list_name( 'A; delete from t_player;--' );
select * from sp_list_name( '''; delete from t_player;--' );

Am I safe ?

Which case I could be injected ?

Regards

+1  A: 

You are not generating SQL for yourself, so this looks safe (to me).

I do not know where the data you are calling your stored procedure is coming from. So you still have to guard against buffer overflows etc.

GvS
Since the VARCHAR is unsized, one has to assume that the DBMS protects itself from buffer overflows. Or, how would the SQL writer modify that code to protect the server from a buffer overflow? Which buffer?
Jonathan Leffler
Since v_temp is set to a User defined input then it is quite possible to do a SQL injection attack unless the input is cleaned at the UI or in the Stored Proc.
Leo Moore
@Jonathan Leffler - The DBMS might be protected. Still you should sanitize the string being send to the DBMS to clear out zero/null characters, extreme length etc. There might be a layer between your app and the DBMS that is vulnarable.
GvS
@Leo Moore: no; the notation passes the v_temp value as a bound parameter, not as part of the string forming the prepared SQL statement. It is not subject to SQL injection. Unless there is something very weird about the way PostgreSQL works...
Jonathan Leffler
@GvS: the DBMS was passed the string as the parameter; the DBMS is responsible for ensuring it doesn't get tripped over the garbage the user might have provided.
Jonathan Leffler
+6  A: 

Rule #1 to prevent against sql injection: Sanitize all input that is coming from someone/something you cannot trust/have no control over.

The problem itself does not lie within the database code, but from the application that is executing those statements.

Jan Jungnickel
+6  A: 

In terms of your procedure you seem safe as the variable in the SP won't be expanded into code, but you can still expose yourself if you don't use a parameterized query like "SELECT * FROM sp_list_name(?);" in your appplication code. Something like "SELECT * FROM sp_list_name('$start_name');" could be subverted by a user passing a start name of "');delete from t_player where last_name NOT IN ('". So use a parameterized query or sanity check your inputs in your program.

NB: To others, please note that a variable in a stored procedure will not expand into code even if it contains a ' or ;, (excluding passing it to EXECUTE, for which you would use quote_literal, not hand-rolled replace functions) so replacing ; or ' is totally unnecessary (in the stored procedure, the application using it is a different story, of course) and would prevent you from always finding the "tl;dr" or "O'Grady" teams.

Leo Moore, Karl, LFSR Consulting: v_temp_name in the stored procedure will NOT be expanded into code in the SP (no EXECUTE), the check would need to be done n the application, not the SP (or the OP could just use a parameterized query in their app code, instead). What others are suggesting is similar to worrying about

my $bar = "foo; unlink('/etc/password');"; 
my $baz = $bar;

actually running the unlink in the absence of an eval.

MkV
Not in the example code, I think - the LIKE would simply fail to match anything except in the extremely unlikely case of an attempted SQL injection exploit having been recorded in the table - because v_temp is a parameter and not pasted into a dynamic SQL string.
Jonathan Leffler
the example code is not the code that the OP has to worry about, their application code would be where to check
MkV
the OP also might want to use something like position instead of hand-rolled like expression, f.e.:SELECT first_name, last_name FROM v_player WHERE position(lower(v_temp) in lower(last_name)) = 1;This would prevent incorrect results if the user passes in a string containing % or _
MkV
ok, to other answers here, to be clear, a variable in a stored procedure will NOT be expanded into code even if it contains ' or ;. It will be treated as a string only (well as a like-expression, but close enough)
MkV
Yes, the possible SQL injection lies the where the SP is called, not within the SP. It pays to parameterize SP calls.
runrig
It would be nice if those claiming otherwise would be voted down instead of up.
MkV
A: 

You could consider validating the content of

 v_start_name 
. Check the string for semi colons, comment chars, equals, etc. Remember to check for both the Chars and the Hex values. Remember to allow for a hyphenated name, e.g. 'Smith-Brown' is likely acceptable 'Smith--Brown' is potentially injection.

If not familiar with Hex in SQL Injection the following are quick intros

http://www.arejae.com/blog/sql-injection-attack-using-t-sql-and-hexadecimal.html

http://www.securityfocus.com/infocus/1768

DECLARE
      v_start_name ALIAS FOR $1;
      r_player  v_player%ROWTYPE;
      v_temp VARCHAR;
   BEGIN
      --  new pseudo code here
      if v_start_name has bad chars exit with error message
      -- end pseudo code here
      v_temp := v_start_name || ''%'';
      FOR r_player IN
         SELECT first_name, last_name FROM v_player WHERE last_name like v_temp
      LOOP
         RETURN NEXT r_player;
      END LOOP;
      RETURN;
   END;

Regards Karl

Karl
Because the user-supplied data is used in a parametized manner, it is not injectable so as to cause code expansion. The DBMS will correctly use all passed chars as a string, regardless of whether they are special-chars or not.
Cheekysoft
See my comment I wrote to Leo Moore. I'm not a fan to replace or forbid characters.Thanks for links
Luc M
A: 

Just do a replace on your v_start_name to get rid of ";" etc. ie

v_clean_name VARCHAR;
Select v_clean_name = Replace(v_start_name,';','');

This will replace the ; with blanks foiling a SQL injection attack

For more details see String Functions in PostgresSQL

As LFSR Consulting has also commented. It is better to WhiteList (ie Do not process any input with invalid characters such a ';') rather than BlackList (ie try to clean the data as the user could do a SQL injection attack on your Replace too).

For more info have a look at SQL Injection Attacks

Leo Moore
Replace on "bad strings" will not work! This is black-listing, to properly prevent sql injection use white-listing.
Gavin Miller
Ok, point taken, so check for invalid chars in the input and skip processing if anything invalid is entered.
Leo Moore
@Leo - sorry if that sounded harsh, that was not my intention.
Gavin Miller
In this specific case, since the query/sp is parameterized, there is no need to filter the input string.
Cheekysoft
I think it's a bad idea to replace a character.What will you do if you want to search a string of text into a very large field ( text often contains ';') ? What will you do if you change the DBMS using another character instead of ';' ?
Luc M
No offence taken LFSR. I appreciate the info. Knowledge is always a good thing and your point is a good one.
Leo Moore
+3  A: 

The proper way to protect against SQL Injection is via White Listing* - the long and short is set the characters that you're going to accept and filter them out.

The incorrect way is to Black List - Black listing what characters aren't accepted is going to lead to trouble, because you can't keep up with attackers. There are ways around black lists via ASCII tables, escape characters and what not.

Also, here's a nice cheat sheet to try out on your site. Run some tests and try to get things to fail.

* In the application, not the DB (Thanks James)

Gavin Miller
+1  A: 

Ref. White Listing. This is OK if certain other conditions are followed. It is absolutely imperative to break all input down into it's simplest form so don't just check for SQL query names, single quotes etc. They can be represented or encoded using other character sets and it's this that forms part of the white list not specifically SQL key words themselves.

I was working for a particular client that allowed username /password to a protected resource (which ultimately could get you an access pass into secure parts of an Airport!). You could circumvent the logon field by entering ' and then building SQL queries from there to retrieve user accounts and passwords.

The problem was the client had already blown £200k building the site with a vendor that appeared to have never done web development before. The fix was a further £60k which was a validate func() that was only checking for union, select, having et al key words. When asked about what they did for canicolisation /encoding (which I had to then explain) it was tumbleweed time.

The Dev house and the (expensive) Project got canned.

Noelie Dunne