1

对于这个项目,我有一个带有表 RESULTS 的数据库文件,如下所示:

conn.execute('''CREATE TABLE RESULTS(
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
age TEXT NOT NULL,
gender TEXT NOT NULL);''')

这是我用来创建原型前端的文件,以便用户可以访问数据库中的数据:

#setting up the user input variables
srcIn = input("what field do you want to search: id, name, age, or gender? ")
srcQuery = input("what result do you want to find from the "+ srcIn + " search? ")
if(srcIn == "age") or (srcIn == "id"):
    #by default input returns a string but it needs to be an int for age and id parameters
    srcQuery = int(srcQuery)
    print("converted to int")
srcOut = input("what field do you want to return: id, name, age, or gender? ")

print("making cursor")
cursor = conn.execute("SELECT %s FROM RESULTS WHERE %s = %s" % (srcOut, srcIn, srcQuery))
for row in cursor:
    print(srcOut + ": " + row[0])

conn.close()
print("closed database " + db)

如果我要运行它并传递年龄或 id、数字 45 和名称,它将完美地从我的数据库中返回名称、性别和其他统计信息。但是,当我传递性别、女性或男性并返回名称或年龄或 ID 时,会弹出一个错误,如下所示:

cursor = conn.execute("SELECT %s FROM RESULTS WHERE %s = %s" % (srcOut, srcIn, srcQuery))
sqlite3.OperationalError: no such column: male

对于这个具体的例子:

srcOut = name
srcIn = gender
srcQuery = male

我尝试将 %s 替换为 ? 参数(我知道它不适用于我传递给 SELECT 语句的参数),所以我很难过。

我认为这与以下事实有关:在某些情况下,我在 srcQuery 字段中将整数传递给它,而在其他情况下,我将其传递给字符串。

任何帮助或建议将不胜感激。

4

1 回答 1

2

不,您不应该按照@Suever 建议的方式进行操作

想象一下,如果我提供以下值,将执行什么查询:

srcOut = "name"
srcIn = "gender"
srcQuery = "' or 1 = 1 -- "

您的代码实际上会执行:

SELECT 
    name 
FROM 
    RESULTS 
WHERE  
    gender = '' or 1 = 1 -- '

这将匹配表中的每一行。

或者,换句话说,由于缺乏任何验证和转义,并且通过准备特定的输入,我将所有结果放在一个表格中,这当然是你不希望在现实世界中发生的事情。这称为SQL 注入攻击

您应该参数化您的查询,而不是字符串格式。查询参数化虽然不适用于表名和列名 - 这些您需要在插入查询之前进行验证 - 因为 和 的可能值的数量scrIn非常srcOut有限 - 如果您看到意外的值,我会简单地抛出一个错误,例如:

columns = {'id', 'name', 'age', 'gender'} 
srcIn = input("what field do you want to search: id, name, age, or gender? ")
if srcIn not in columns:
    raise ValueError("Invalid srcIn value")

至于srcQuery- 这个你需要参数化

query = "SELECT {column_out} FROM RESULTS WHERE {column_in} = ?".format(column_out=srcOut, column_in=scrIn)
cursor = conn.execute(query, (srcQuery, ))

除了更安全之外,这还消除了考虑 python 到数据库类型转换和引号的问题——数据库驱动程序会自动处理这些问题。

于 2016-12-10T04:15:03.793 回答