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.) |