我希望用户能够选择显示的订单结果(例如按年龄),并且我不想在从数据库中获取它们后对其进行排序。
显然,如果用户能够指定影响SQL命令的输入,则需要对其进行过滤,并且我通常会使用参数化,但是pysqlite似乎会忽略除值以外的任何参数。
下面的示例代码显示了不适用于的参数设置ORDER BY,以及使用字符串格式的解决方法,但这种方法容易受到SQL注入的攻击。
ORDER BY
建议的解决方案是什么,以允许用户输入在不暴露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 ...)。)
ORDER BY password
ORDER BY (SELECT ... FROM OtherTable ...)
为了确保来自客户端的列名有效,您可以使用白名单:
if order_by not in ['name', 'age']: raise ... execute('... ORDER BY {}'.format(order_by))
但是将字符串集成到查询中仍然是一个坏主意,因为验证和实际表可能不同步,或者您可能忘记了检查。最好从客户端返回一个列索引,以便您使用的实际字符串始终是您自己的,并且在正常测试期间可以轻松发现任何错误:
order_by = ['name', 'age'][order_index] execute('... ORDER BY {}'.format(order_by))