python - 如何从pyodbc中的用户获取表名,同时避免SQL注入(inject)?

标签 python sql sql-server python-3.x pyodbc

我有以下代码,它是完全安全的,用户无法输入任何可能导致 SQL 注入(inject)的内容。

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

但是如果我需要从用户那里获取表名怎么办?我不能这样做,因为这会让我容易受到 SQL 注入(inject)的攻击;

table_name = get_table_name_from_user_input()
query = \
    f"""
    SELECT *
    FROM {table_name}
    WHERE CompareValue = 1234
    """
cursor.execute(query)

而且我也不能这样做(在我看来这是合乎逻辑的),因为它会给出错误。

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

那么我应该怎么做呢?

额外信息:

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

最佳答案

您可以使用 pyodbc 的 Cursor#tables 直接从数据库获取有效表名的列​​表。功能:

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

正如您所指出的,您不能使用参数为查询提供对象(例如表或列)名称,但您可以使用 T-SQL QUOTENAME函数来帮助确保您构建的(动态)SQL 有效。

您留意可能的 SQL 注入(inject)问题是件好事,但并非所有动态 SQL 都是邪恶的。有时,就像在本例中一样,这是必要的;您只需要采取适当的措施来保护自己。

关于python - 如何从pyodbc中的用户获取表名,同时避免SQL注入(inject)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55853739/

相关文章:

Python 2.x 与 3.x 导入,具体取决于调用/导入脚本的位置

python - Tkinter radiobutton IntVar 属性错误

java - 无法第二次执行表更改事件

php mysql 这里有什么问题

java - 如何查询具有复合主键的表

sql-server - 为什么 FOR 子句不能与具有时态表的 SQL Server 2016 中的别名一起使用?

sql-server - 将 UTF-8 varbinary(max) 转换为 varchar(max)

python - 获取网页字符集的好用、可靠的快捷方式是什么?

python - 模型表单中的 Django 必填字段

python - 在 sql server 上运行 python(.py 脚本)