Such as? If you only use PreparedStatment (Java), or the equivalent for your language, and have a rule against, and never broken, to concatenate SQL strings together, you are safe from SQL injection.
There are options available as one or more of the above 3 requirements is dropped: http://stackoverflow.com/questions/149380/dynamic-sorting-wi...
Paging is equally easy, using ROWNUM < X in Oracle or equivalent in other RDBMS.
The order by is a good point. The obvious solution here would be to always have the same sorting as default, and do the user sorting client side (by client here, I mean calling application).
Do you agree that this is a scenario requiring dynamic SQL?
This is somewhat less efficient, but if the alternative is to be open to sqli attacks it'd be my pleasure.
Congratulations, we are no longer relying on bound parameters to prevent SQL injection. THREAD FINISHED! :)
(See another person discussing this here in this thread: http://news.ycombinator.com/item?id=4203929 )
I do not allow the client direct access to the database. They access the database through objects, which have methods that only permit parameterized input.
The client cannot specify the database, table, or columns. That is hard-coded. They can only specify values. Values that are always entered through a prepared statement.
In that scenario, isn't injection impossible?
I've implemented a [complex?] white-listing solution to a problem in a domain where there is a long history of developer mistakes, passing user input to a 3rd-party technology most developers only know the minimum required for their job. Isn't injection impossible?
Edit: Sorry for any confusion; this was my way of saying 'this is only bulletproof if you got every edge case 100% right; few security experts make guarantees of impossibility of failure'.
Also code review, of which there will be need for plenty, when bare minimum developers is involved.
Obviously, you can write simple code to do each of these safely. But then, you can write simple code to handle query parameters too.
By all means, use parameterized queries. Just don't assume they're a magic totem against SQLI.
For example the following example from http://de.php.net/manual/en/sqlite3.prepare.php :
$stmt = $db->prepare('SELECT bar FROM foo WHERE id=:id');
$stmt->bindValue(':id', 1, SQLITE3_INTEGER);
$stmt = $db->prepare('SELECT bar FROM foo
LIMIT :offset, :count');
...
You can't do that. You can only bind data to fields. $stmt = $db->prepare('SELECT bar FROM foo
ORDER BY :column :direction');
$stmt->bindValue(':column', 'foo');
$stmt->bindValue(':direction', 'DESC');
You can't do that either, because again, it's not data.So, you end up having to do something similar to this (for the love of god, don't actually do this):
$stmt->prepare("SELECT bar FROM foo WHERE id = :id
ORDER BY {$column} {$direction}
LIMIT {$offset}, {$count}");
Bound parameters won't save you, and the potential attack vector is there if you're not really careful. That example shows the most stupid thing you could ever do, so don't do it.Even if the DB interface doesn't directly support this, it seems like it's something all client wrappers should handle, preferably at the low level in addition to having to pull in a whole ORM + assorted bacon for the purpose.
That would not have been a "real" prepared statement in my mindset so I get why I was confused.
I don't feel super smart, but wouldn't I simply make sure that $column is a valid column (ok, that one might need extra attention) and $direction would be either ASC or DESC and that $offset and $count are integers?
The lexical structure of the statement and the parameters themselves are two different things. You are correct that "parameterization can't save you from SQL injection", if you're such a bad programmer that you're feeding user input directly to produce lexical tokens. One example is a recent blog post talking about how to escape table names for apps that feed things like "customer_name" to serve as the table name (totally insane). Your example of feeding in "sort=xyz" to produce the column name in the ORDER BY is also a pretty awful practice - I haven't seen that one in like a decade, but sure.
So of course parameterization doesn't magically protect a system against all forms of attack - the programmer could be feeding user input directly into shell commands too. The recommendation for parameterization is addressing the bulk of the issue at least among the code that I regularly work with, maybe you deal with crappier programmers than I do on a regular basis.
This still happens every day. Google how to do dynamic sorting and you'll find a hundred examples of it in PHP, and as unfortunate as it is, that's how a significant portion of code is authored.
The better answer is a parameterized query, which actually controls the inputs properly to ensure that no dynamic SQL is possible.
SELECT sp_enroll("bob\"); DROP TABLE students; --");
or SELECT sp_enroll("bob"); DROP TABLE students; --");
?At least if you grant the user only SELECT and EXECUTE privileges and define the procedures using the SECURITY DEFINER property, you could still prevent this type of damage. (This relies on the procedures to be as strict as possible or the whole scheme essentially fails.)