I'm developing a relatively small application to talk to PostgreSQL, and wanted to get some feedback on how far is too far to go with regards to protecting against SQL injection.
The application is in Perl and does not use any ORM modules (just DBI). The SQL statements are constructed in the typical fashion with placeholders:
my $sql = "SELECT * FROM $cfg->{tablename} WHERE foo = ?";
my $sth = $dbh->prepare($sql);
$sth->execute('bar');
The reason the tablename is interpolated is that the application has to perform the same operation against multiple tables, all of which have a column 'foo'.
Using the ? placeholder protects against most of the simple SQL injection attacks. My question is around the tablename, which you can't use a placeholder for. The table comes from the config file, but the app supports a --configfile switch to use an alternate config file.
The database credentials are stored in the config file. So if an attacker could craft a config file (or replace the default one) with one in which $cfg->{tablename} was replaced with something malicious, then the application could be "tricked" into running the malicious code.
For an attacker to do this, they'd have to have valid database credentials already, otherwise the application wouldn't connect. If they have credentials, then they can just craft their own code using DBI or use the psql cli to do something malicious.
I see two possible ways to protect against this:
Obviously the second way is the "cheap and cheerful" one. But given the statement about credentials above, are either of these approaches really warranted? How much effort is too much when it comes to forcing the attacker to just use an alternate attack vector (as opposed to effort that actually prevents the attack?
use quote_identifier:
my $sql = "SELECT * FROM ".
$dbh->quote_identifier($cfg->{tablename}).
" WHERE foo = ?";
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With