我应该如何在 pysqlite 中参数化列名以避免 SQL 注入

How should I parameterize column names in pysqlite to avoid SQL Injection

我希望用户能够选择显示哪些订单结果,例如按年龄),我不想在从数据库中获取它们后对它们进行排序。

显然,如果用户能够指定影响 SQL 命令的输入,则需要对其进行清理,我通常会使用参数化,但 pysqlite 似乎忽略除值之外的任何参数。

下面的示例代码显示参数化不适用于 ORDER BY,还有一个使用字符串格式的变通方法,但这容易受到 SQL 注入的影响。

允许用户输入影响排序顺序而不暴露 SQLi 漏洞的推荐解决方案是什么?我是否必须使用字符串格式并手动检查每个用户输入?

#!/user/bin/env python3

import sqlite3

con = sqlite3.connect(':memory:')
cur = con.cursor()
cur.execute('CREATE TABLE test (name, age)')
cur.execute('INSERT INTO test VALUES (:name, :age)', {'name': 'Aaron', 'age': 75})
cur.execute('INSERT INTO test VALUES (:name, :age)', {'name': 'Zebedee', 'age': 5})

cur.execute('SELECT * FROM test ORDER BY age ASC')
results = cur.fetchall()
print('\nGood, but hard coded:\n', results)
# Good, but hard coded:
#  [('Zebedee', 5), ('Aaron', 75)]

cur.execute('SELECT * FROM test ORDER BY :order_by ASC', {'order_by': 'age'})
results = cur.fetchall()
print('\norder_by parameter ignored:\n', results)
# order_by parameter ignored:
#  [('Aaron', 75), ('Zebedee', 5)]

cur.execute('SELECT * FROM test ORDER BY {order_by} ASC'.format(order_by='age'))
results = cur.fetchall()
print('\nRight order, but vulnerable to SQL injection:\n', results)
# Right order, but vulnerable to SQL injection:
#  [('Zebedee', 5), ('Aaron', 75)]

con.close()

SQL 参数仅用于值;其他任何事情都可能改变查询的含义。 (例如,ORDER BY password 可以留下提示,ORDER BY (SELECT ... FROM OtherTable ...) 也可以。)

为确保来自客户端的列名有效,您可以使用白名单:

if order_by not in ['name', 'age']:
    raise ...
execute('... ORDER BY {}'.format(order_by))

但是将该字符串集成到查询中仍然是一个坏主意,因为验证和实际 table 可能会不同步,或者您可能会忘记检查。最好return一个来自客户端的列索引,这样你实际使用的字符串始终是你自己的,并且在正常测试期间可以很容易地发现任何错误:

order_by = ['name', 'age'][order_index]
execute('... ORDER BY {}'.format(order_by))