SQL注入安全调用多态函数

时间:2015-02-18 04:19:04

标签: database postgresql sql-injection plpgsql dynamic-sql

有几次我发现自己重构了Web应用程序代码并最终想要做这样的事情(在这种情况下是Groovy,但可能是任何东西):

Map getData(String relationName, Integer rowId) {
    def sql = Sql.newInstance([...])
    def result = sql.firstRow('SELECT getRelationRow(?,?)', relationName, rowId)
    sql.close()
    return new HashMap(result)
}

其中存储过程getRelationRow(relname text, rowid integer)执行动态sql以检索所请求关系中指定的rowid的行。我见过这样一个函数的最好例子是this polymorphic function使用anyelement类型,并被称为

SELECT * FROM data_of(NULL::pcdmet, 17);

但是要在上面的代码中调用它需要

def result = sql.firstRow("SELECT * FROM data_of(NULL::${relationName},?)",  rowId)

也就是说,它需要将关系名称粘贴到查询中,这会冒SQL注入的风险。那么保留存储过程的多态性,还是允许使用通用关系名称来调用它?

1 个答案:

答案 0 :(得分:1)

我认为不能这样做。我假设Groovy在这里使用预处理语句,这要求在准备时知道输入和返回类型,而我的函数从多态输入类型派生返回类型。

我很确定你需要字符串连接。但是不要担心,有像pg_escape()这样的函数来清理表名并使SQLi不可能。不知道Groovy,但也应该知道。

或者是吗?

基于此相关答案末尾的函数data_of(..)

使用PREPARE我可以通过明确声明返回类型来完成这项工作:

PREPARE fooplan ("relationName") AS  -- table name works as row type
SELECT * FROM data_of($1, $2);

然后我可以将NULL提交给准备好的上下文中的"relationName"

EXECUTE fooplan(NULL, 1);

如果您的界面支持这一点,那么这可能会起作用。但是您仍然必须将表名连接为返回数据类型(因此可以防御SQLi)。抓住22我想。