Python cursor.execute() with MySQL UPDATE 导致语法错误

Python cursor.execute() with MySQL UPDATE causes syntax error

按照 this 示例,我正在尝试重写与防止 SQL 注入的代码一起工作的代码:

有效代码:

table = "led_status"
field = "test_led"
value = "FALSE"

cursor.execute(("UPDATE %s SET %s = %s") % (table, field, value))

无效代码:

table = "led_status"
field = "test_led"
value = "FALSE"

cursor.execute(("UPDATE %s SET %s = %s", table, field, value))

此代码也不起作用:

table = "led_status"
field = "test_led"
value = "FALSE"

sql_update_command = "UPDATE %s SET %s = %s"
cursor.execute(sql_update_command, (table, field, value))

第一个示例有效,其他示例无效,每个示例都抛出此语法错误:

mysql.connector.errors.ProgrammingError: 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''led_status' SET 'test_led' = 'FALSE'' at line 1

我不确定我做错了什么,所以任何指点将不胜感激。

您的 SQL 在所有 3 个示例中都不正确。 以下代码应该有效:

table = "led_status"
field = "test_led"
value = False

cursor.execute("UPDATE `%s` SET `%s` = %s", (table, field, value))

请注意 table 和列名称周围的反引号 (`),但是,值应表示为列各自的对象类型。应使用单引号和双引号来表示字符串值。

在您的情况下,FALSE 很可能不应该存储为字符串,而是数据库模式中的布尔值或 tinyint。

我喜欢将 psycopg2 用于这样的实例,在这种情况下,您尝试将列名称作为输入提供并且不希望它转义

from psycopg2.extensions import AsIs

cmd = """
      UPDATE %(table)s SET %(column)s = %(val)s
      """

kwargs = {
    'table': AsIs('led_status'),
    'column': AsIs('test_led'),
    'val': False
}

cursor.execute(cmd, kwargs)

感谢您的提示。最终我在阅读这篇 post 后发现了我的错误。显然你不能参数化一个 table 名字!

这就是我修复代码的方式:

table = "led_status"
field = "test_led"
value = "FALSE"

sql_update = "UPDATE " + table + " SET " + column + " = %s"
cursor.execute(sql_update, (value,))

根据文档执行此操作的最佳方法是:

from psycopg2 import sql

cur.execute(
sql.SQL("insert into {} values (%s, %s)")
    .format(sql.Identifier('my_table')),
[10, 20])

Source

由于您的问题是关于 SQL 注射的,所以我会更进一步,而不是给您一个衬垫。您的问题是您无法参数化 table 名称。在处理 SQL 注入时,您必须区分动态 SQL 和用户输入值之间的区别。转义值以防止 SQL 注入应该由驱动程序的 quote/escaping 机制处理。您正在自行验证动态 SQL 片段。动态 SQL 片段包括变量 WHERE 条件表达式、变量 table 名称或变量 SELECT 字段列表。

您示例的正确语法是:

cursor.execute("UPDATE {} SET {} = %s".format(table, field), value)

cursor.execute("UPDATE %s SET %s = %%s" % (table, field), value)

但是,如果 table 确实来自用户,您必须在执行此语句之前根据某些预定义列表对其进行验证。您不能相信数据库会用 table 名称或字段名称做正确的事情。例如,以下数据结构将提供一些验证依据。

valid_fields = {
   'table_1': ['field_1', 'field_2'],
   'table_2': ['field_a', 'field_b'],
   'table_3': ['field_x', 'field_y']
}

您也可以使用数据库提供的特殊目录 table(例如 pg_catalog)来动态获取这些内容,但您仍应检查特殊的 field/table 名称(例如 OID ).