生成SQL"IN"子句:如何安全地处理输入+空值列表?

lar*_*els 2 python mysql sql sql-injection

在我的Python代码中,我经常发现自己正在执行以下操作(使用DB-API):

yValues = pickInterestingValuesOfY()

sql = "..." # includes a clause stating that "y must be in yValues"

c.execute(sql, yValues)
Run Code Online (Sandbox Code Playgroud)

最后,正在执行的SQL可能很简单

SELECT x FROM table1 WHERE y IN (1,2,3);
Run Code Online (Sandbox Code Playgroud)

问题是y(1,2,3)的可能值集在运行时确定.

我有两个问题:

  1. 在yValues为空的情况下生成有效的SQL('WHERE y IN()'是无效的SQL)
  2. 如果值来自不受信任的源,请注意sql注入

要解决(2)我必须让DB-API实际将yValues插入到SQL语句中.所以我最终得到了以下复杂的解决方案:

def inClause(columnName, values):

    if len(values):
         placeHolders = ','.join( ['%s'] * len(values) )
         sql = "%s IN (%s)" % (columnName, placeHolders)
    else: 
         sql = "FALSE"
    return "(%s)" % sql

# get a db-api cursor called c
c.execute("SELECT x FROM table1 WHERE %s;" % inClause('y', yValues), yValues)
Run Code Online (Sandbox Code Playgroud)

这似乎正确地解决了上述两个问题.但是,我无法相信这个笨重的解决方案是需要的.

你如何处理这样的问题?我错过了更优雅的方式吗?

我不是在寻找ORM.

(我正在使用MySQL,所以如果有一些神奇的mysql非标准开关默认接受'WHERE y IN()'为有效,请让我知道并关注(1)将被处理.)

Rod*_*man 5

对于in子句,只需要包含一个不在列表中的值(例如,一个负整数).