Как мне параметризовать имена столбцов в pysqlite, чтобы избежать инъекции SQL

Я хочу, чтобы пользователь мог выбирать, какие результаты заказа будут отображаться, например. по возрасту), и я не хочу сортировать их после получения из базы данных.

Очевидно, что если пользователь может указать ввод, который влияет на команды 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()

person Grezzo    schedule 25.01.2017    source источник
comment
Кстати, я только что попытался использовать SQLi с этим вводом 'age; DROP TABLE test;--' для третьей команды SQL, и pysqlite вызвал исключение, говорящее sqlite3.Warning: You can only execute one statement at a time., так что, может быть, мне не стоит беспокоиться? Мне все еще кажется, что использование форматирования строк опасно, хотя...   -  person Grezzo    schedule 25.01.2017
comment
Может ли пользователь каким-либо образом повлиять на фактическое содержимое строки? (В вопросе вы используете постоянную строку 'age', что не имеет смысла.)   -  person CL.    schedule 25.01.2017
comment
Это исходит из http-запроса. Если они используют надлежащий клиент (веб-страницу), это должно быть любое 1 из 6 имен столбцов, но если кто-то решит действовать злонамеренно, это может быть что угодно по их выбору.   -  person Grezzo    schedule 25.01.2017


Ответы (1)


Параметры SQL используются только для значений; что-либо еще может изменить смысл запроса. (Например, 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))
person CL.    schedule 25.01.2017
comment
Используйте константу, чтобы задать значения order_index имен (например, NAME_COLUMN = 0). Таким образом, вы можете легко добавлять дополнительные столбцы или перемещать их, а также видеть, какой порядок вы хотите. - person Aaron Digulla; 25.01.2017
comment
Также обратите внимание, что вы можете легко создавать более сложные порядки, такие как name ASC, age DESC, присваивая им собственный индекс. - person Aaron Digulla; 25.01.2017
comment
Отличный ответ, особенно пример упорядочения по столбцам может дать подсказки для пароля. Спасибо. Белый список есть тогда. - person Grezzo; 25.01.2017