【问题标题】:"Delete from" deletes everything“删除”删除所有内容
【发布时间】:2021-01-05 12:18:41
【问题描述】:

我有一个python函数,它使用name属性作为条件删除mysql表中的一行:

def delete(table: str, name: str):
    cursor.execute(f"DELETE FROM {table} WHERE name = {name}")
    conn.commit()

我有一排 name 属性等于“名称”。当我将此函数与“名称”一起使用时,它会删除表中的每一行。

我猜这与传递的字符串与属性相同有关。但是除了重命名属性之外,该问题的解决方案是什么?

【问题讨论】:

  • 您尝试打印出 SQL 吗?
  • 您没有在 {name} 周围缺少引号吗?
  • 我没想到表名和列名可以这样绑定;只应注入 WHERE 子句值。您观察到的行为是如果未添加 WHERE 子句会发生什么。我会确保生成的 SQL 是您错误假设的。这对我来说似乎很危险——SQL 注入攻击的时机已经成熟。
  • @duffymo 表名仅在代码内部使用。我要防止注入的是属性名称,因为它使用用户的输入。
  • 不应以这种方式绑定表名和列名。坏主意。

标签: python sqlite sql-delete


【解决方案1】:

因此,我认为您在名称周围缺少引号以及分号。

如需进一步阅读,您还应该查看Python parameterized query and Prepared Statement

我同意 cmets,出于安全原因,该表不应该是注入参数!

def delete(table: str, name: str):
    query = f"DELETE FROM {table} WHERE name = ?"
    print(query)
    cursor.execute(query, (name,))
    conn.commit()`

编辑完整的工作示例:

import sqlite3            
conn = sqlite3.connect("test")

query_create = '''CREATE TABLE IF NOT EXISTS projects (
    id integer PRIMARY KEY,
    name text NOT NULL,
    begin_date text,
    end_date text
);'''
    
conn.execute(query_create)

query_insert = '''insert into projects (id, name, begin_date, end_date) values (1,"name","date","date")'''

conn.execute(query_insert)
query_select = '''select * from projects'''

cur = conn.execute(query_select)
print(cur.fetchall())


def delete(table: str, name: str):
    query = f"DELETE FROM {table} WHERE name = ?"
    print(query)
    conn.execute(query, (name,))

    
delete('projects', 'name')

cur = conn.execute(query_select)
print(cur.fetchall())

给出输出:

[(1, 'name', 'date', 'date')]
DELETE FROM projects WHERE name = ?
[]

【讨论】:

  • 你让 SQL 注入的可能性比它需要的更开放。使用query = f"DELETE FROM {table} WHERE name = %s",然后使用cursor.execute(query, (name,)) 进行参数化查询。仍然table 不应该使用不受信任的来源。
  • 试过你的代码它返回sqlite3.OperationalError: near "%": syntax error
  • 打印返回什么?
  • DELETE FROM categories WHERE name = %s
  • 现在可以试试吗?