如何在pyodbc中从用户处获取表名,同时避免SQL注入?

2024-06-28 22:02:26 发布

您现在位置:Python中文网/ 问答频道 /正文

我有以下代码,这是完全安全的,用户不能输入任何可能导致SQL注入。在

value = get_value_from_user_input()
query = \
    """
    SELECT *
    FROM TestTable
    WHERE CompareValue = ?
    """
cursor.execute(query, value)

但是如果我需要从用户那里获得表名呢。我不能这样做,因为这让我很容易受到SQL注入的影响

^{pr2}$

我也不能这样做(这在我看来是合乎逻辑的),因为这会产生错误。在

table_name = get_table_name_from_user_input()
query = \
    """
    SELECT *
    FROM ?
    WHERE CompareValue = 1234
    """
cursor.execute(query, table_name)

那我该怎么做呢?在

额外信息:

该程序是在我的公司内使用,所有用户的软件都有管理权的数据库。不允许它们注入SQL可能有点毫无意义,因为它们无论如何都可以执行原始SQL查询。我只想变得迂腐,不允许我的程序执行随机SQL。get_table_name_from_user_input()实际上从描述数据库结构的配置文件中获取表名,因此,如果某一天数据库中的表名发生更改,则用户可以轻松地对其进行编辑,而无需接触源代码。在


Tags: 用户namefrom数据库inputsqlgetvalue
2条回答

如果没有太多的表,可以检查请求的表名是否存在于有效表名的列表中。在

tables = ["customers", "vendors", "products"]

user_inputs = ["products", "invoices", "vendors WHERE CompareValue=1234; DROP TABLE customers;  "]

query = "SELECT * FROM placeholder WHERE CompareValue=1234;"

for user_input in user_inputs:
  if user_input in tables:
    print(query.replace("placeholder", user_input))
  else:
    print(f"'{user_input}' is not a valid table")

给出了以下结果

^{pr2}$

repl中的此代码段:https://repl.it/repls/SeveralAnimatedAutomaticvectorization

可以使用pyodbc的Cursor#tables函数直接从数据库中获取有效表名的列表:

crsr = cnxn.cursor()
table_names = [x[2] for x in crsr.tables(tableType='TABLE')]
print(table_names)  # ['customer', 'invoice', ...]

正如您所注意到的,您不能使用参数为查询提供对象(例如,表或列)names,但可以使用t-SQLQUOTENAME函数来帮助确保所构造的(动态)SQL是有效的。在

注意可能的SQL注入问题是件好事,但并非所有的动态SQL都是邪恶的。有时候,就像在这种情况下,这是必要的;你只需要采取适当的措施来保护自己。在

相关问题 更多 >