in reply to Re^2: perl SQL injection prevent module
in thread perl SQL injection prevent module

Maybe you could try turning on "taint mode" by putting "-T" on the shebang line of the script, or simply running the script from the command line as follows:
perl -T your_script [args...]
(Update: just noticed the later reply from tantarbobus -- heed that as well.)

That might be overkill, because it will cause perl to complain (and the script to die) if any variable derived from outside the script is used to affect anything else outside the script. This should include passing tainted variables to DBI calls, along with a wide variety of other things. See perlsec for more details about taint-checking.

If you go that route, you'll probably end up fixing a lot of other things besides potential SQL injection attacks. And maybe this would be a Good Thing -- if such attacks are a serious concern for you, then there might be other things to worry about as well. It'll end up being "invasive", but better that you should be the invader than someone else. ;)

You might want to do some triage on the script, to assess how much work needs to be done: just grep through the code for calls to the DBI methods that pass SQL text (prepare, do, select.*), to see how many different variables are being passed to these methods. (If all these calls involve string constants, you're done -- no room for injection attacks in that case.) Then you have to track down where and how values are being assigned to those variables.

If you are seeing a lot of situations like this:

$sql = "select * from some_table where some_col = $target"; $sth = $dbh->prepare( $sql ); $sth->execute; ...
You'll want to change those to:
$sql = "select * from some_table where some_col = ?"; $sth = $dbh->prepare( $sql ); $sth->execute( $target );
But if variables are being used like this:
$sql = "select $colum from $table";
and those variables are set by input from untrusted sources, then the only real protection is to untaint those values.

Probably the best way is to set up a hash of column names and/or table names as needed (or a hash of whole query strings), then check each input to see if its value exists as a hash key. If so, use the hash value (which originates in your own code and so can be trusted) in order to form the query -- e.g.:

my $cols = ( foo => 'foo', bar => 'bar', baz => 'baz' ); my $tbls = ( parts => 'parts', table2 => 'table2' ); my $inp_col = <USER>; # get data from untrusted sources my $inp_tbl = $ENV{TABLE}; if ( exists( $cols{$inp_col} ) and exists( $tbls{$inp_tbl} ) { my $sql = "select $cols{$inp_col} from $tbls{$inp_tbl}"; # now it's safe to run the query... }
(update: added the necessary quotes around hash value assignments in this code snippet.)

Replies are listed 'Best First'.
Re^4: perl SQL injection prevent module
by Anonymous Monk on Nov 21, 2008 at 23:12 UTC
    Right ... here is the WRONG example in Perl ... CODE: my $count; my $crypt_pass1 =crypt($args{pass},$args{username}); my $sth = $dbh->prepare("SELECT COUNT(id) FROM users WHERE username = '$args{username}' AND password ='$crypt_pass1'"); $sth->execute(); $sth->bind_columns(\$count); $sth->fetch; # If this counter count 1 --> there is a true combination if ($count == 1){ the result is: if you enter the following username (even without pass): xxx' or id ='1'# the counter will count 1 (true) for user with ID 1 ... the password is commented ... and we obtain the following mysql query: SELECT COUNT(id) FROM users WHERE username = 'xxx' or id = '1'# AND password ='$crypt_pass'