提问人:Diurnambule 提问时间:7/11/2022 更新时间:7/13/2022 访问量:437
SQL 数据格式化和 SQL 注入
sql data formatting and sql injections
问:
我有一个包含 2 个表的数据库:我想更新其中一个表:students, employees
import sqlite3
db_file = "school.db"
def update_address(identifier, user_address, user_id):
with sqlite3.connect(db_file) as conn:
c = conn.cursor()
c.execute(f"""
UPDATE {identifier}
SET address = ?
WHERE id = ?;
""",
(user_address, user_id))
update_address("students", "204 Sycamore Street", 2)
上面的代码有效,问题是我知道在 sql 操作中使用 python 字符串格式可能会导致每个 sqlite3 文档的漏洞:
通常,您的 SQL 操作需要使用 Python 变量中的值。不应使用 Python 的字符串操作来组装查询,因为这样做是不安全的;它使您的程序容易受到 SQL 注入攻击(有关可能出错的幽默示例,请参阅 https://xkcd.com/327/)。
请改用 DB-API 的参数替换。放?作为要使用值的任何位置的占位符,然后提供值的元组作为游标的 execute() 方法的第二个参数。
占位符“?”在插入值时有效,但不适用于 sql 标识符。输出:sqlite3.OperationalError: near "?": syntax error
所以这里的问题是:如果我在 sql 标识符上使用 python 字符串格式,是否会发生 sql 注入,或者它是否只发生在值上?
如果它也发生在标识符上,有没有办法以安全的方式格式化字符串?
答:
是的,如果您不安全地将任何内容插入 SQL 查询,则属于 SQL 注入漏洞。无论内容是否应该用作 SQL 表达式中的值,还是标识符、SQL 关键字或其他任何内容,都无关紧要。
如果要编写具有一组可变条件的查询,则从 SQL 表达式片段中格式化查询是很常见的。这些也是可能的 SQL 注入风险。
降低 SQL 注入风险的方法是:不要将不受信任的输入插入到 SQL 查询中。
对于标识符,应确保内容与表(或列或其他元素,如果这是您尝试动态的)的合法名称匹配。即,创建一个“允许使用函数更新的数据库中已知存在的表的”允许列表”。如果输入与其中之一不匹配,则不要运行查询。
使用反引号来分隔标识符也是一个好主意,因为如果其中一个表名恰好是 SQLite 中的保留关键字,这将允许在 SQL 查询中使用该表。
if identifier not in ["table1", "table2", "table3"]:
raise Exception("Unknown table name: '{identifier}'")
c.execute(f"""
UPDATE `{identifier}`
SET address = ?
WHERE id = ?;
""",
(user_address, user_id))
评论