问题
Several times I've found myself refactoring web application code and end up wanting to do something like this (Groovy in this case, but could be anything):
Map getData(String relationName, Integer rowId) {
def sql = Sql.newInstance([...])
def result = sql.firstRow('SELECT getRelationRow(?,?)', relationName, rowId)
sql.close()
return new HashMap(result)
}
where the stored procedure getRelationRow(relname text, rowid integer)
executes dynamic sql to retrieve the row of the specified rowid
in the requested relation. The best example I've seen of such a function is this polymorphic function using anyelement
type, and is called as
SELECT * FROM data_of(NULL::pcdmet, 17);
However to call this in the above code would require
def result = sql.firstRow("SELECT * FROM data_of(NULL::${relationName},?)", rowId)
that is, it required the relation name to be pasted into the query, which risks SQL Injection. So is there away to keep the polymorphic goodness of the stored procedure but allow it to be called with generic relation names?
回答1:
I don't think it can be done this way. I assume Groovy is using prepared statements here, which requires that input and return types are known at prepare time, while my function derives the return type from the polymorphic input type.
I am pretty sure you need string concatenation. But don't fret, there are functions like pg_escape()
to sanitize table names and make SQLi impossible. Don't know Groovy, but it should have that, too.
Or does it?
Based on the function data_of(..)
at the end of this related answer:
- Refactor a PL/pgSQL function to return the output of various SELECT queries
With PREPARE I can make this work by declaring the return type explicitly:
PREPARE fooplan ("relationName") AS -- table name works as row type
SELECT * FROM data_of($1, $2);
Then I can hand in NULL
, which is cast to "relationName"
from the prepared context:
EXECUTE fooplan(NULL, 1);
So this might work after all, if your interface supports this. But you still have to concatenate the table name as return data type (and therefore defend against SQLi). Catch 22 I guess.
来源:https://stackoverflow.com/questions/28575899/sql-injection-safe-call-of-polymorphic-function